From 9e78d14a9f641c0476f733f6fc559ba5cac6f52b Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 10 Dec 2013 15:26:48 +0000 Subject: [PATCH 0001/5088] Use %pd in eCryptFS Use the new %pd printk() specifier in eCryptFS to replace passing of dentry name or dentry name and name length * 2 with just passing the dentry. Signed-off-by: David Howells cc: ecryptfs@vger.kernel.org Signed-off-by: Tyler Hicks --- fs/ecryptfs/file.c | 4 ++-- fs/ecryptfs/inode.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index b1eaa7a1f82c..c705360e2b16 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -230,8 +230,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file) if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " - "[%s]; rc = [%d]\n", __func__, - ecryptfs_dentry->d_name.name, rc); + "[%pd]; rc = [%d]\n", __func__, + ecryptfs_dentry, rc); goto out_free; } if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index c36c44824471..87ad33e091e9 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -250,8 +250,8 @@ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " - "[%s]; rc = [%d]\n", __func__, - ecryptfs_dentry->d_name.name, rc); + "[%pd]; rc = [%d]\n", __func__, + ecryptfs_dentry, rc); goto out; } rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); @@ -313,8 +313,8 @@ static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode) if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " - "[%s]; rc = [%d]\n", __func__, - dentry->d_name.name, rc); + "[%pd]; rc = [%d]\n", __func__, + dentry, rc); return rc; } @@ -418,8 +418,8 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " - "[%d] on lower_dentry = [%s]\n", __func__, rc, - ecryptfs_dentry->d_name.name); + "[%d] on lower_dentry = [%pd]\n", __func__, rc, + ecryptfs_dentry); goto out; } if (lower_dentry->d_inode) -- GitLab From c4cf3ba4f34819170fee43532f729e2fc6aa9a76 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Fri, 27 Jun 2014 01:11:59 +0530 Subject: [PATCH 0002/5088] ecryptfs: Drop cast This patch does away with cast on void * and the if as it is unnecessary. The following Coccinelle semantic patch was used for making the change: @r@ expression x; void* e; type T; identifier f; @@ ( *((T *)e) | ((T *)x)[...] | ((T *)x)->f | - (T *) e ) Signed-off-by: Himangi Saraogi Signed-off-by: Tyler Hicks --- fs/ecryptfs/inode.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 87ad33e091e9..a27121d35b23 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -53,9 +53,7 @@ static void unlock_dir(struct dentry *dir) static int ecryptfs_inode_test(struct inode *inode, void *lower_inode) { - if (ecryptfs_inode_to_lower(inode) == (struct inode *)lower_inode) - return 1; - return 0; + return ecryptfs_inode_to_lower(inode) == lower_inode; } static int ecryptfs_inode_set(struct inode *inode, void *opaque) -- GitLab From 3db593e8af0a7361037a2abbe8910d4e44041d89 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 16 Jun 2014 20:06:12 +0200 Subject: [PATCH 0003/5088] fs/ecryptfs/messaging.c: remove null test before kfree Fix checkpatch warning: WARNING: kfree(NULL) is safe this check is probably not required Signed-off-by: Fabian Frederick Cc: ecryptfs@vger.kernel.org Signed-off-by: Tyler Hicks --- fs/ecryptfs/messaging.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index e57380e5f6bd..286f10b0363b 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c @@ -434,8 +434,7 @@ void ecryptfs_release_messaging(void) mutex_lock(&ecryptfs_msg_ctx_lists_mux); for (i = 0; i < ecryptfs_message_buf_len; i++) { mutex_lock(&ecryptfs_msg_ctx_arr[i].mux); - if (ecryptfs_msg_ctx_arr[i].msg) - kfree(ecryptfs_msg_ctx_arr[i].msg); + kfree(ecryptfs_msg_ctx_arr[i].msg); mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux); } kfree(ecryptfs_msg_ctx_arr); -- GitLab From 27199b15e4f027e24969f6644ce4ff414c7e6cba Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 18 Jun 2014 21:15:59 -0400 Subject: [PATCH 0004/5088] ecryptfs: Remove unnecessary include of syscall.h in keystore.c There's no reason to include syscalls.h in keystore.c. Remove it. Signed-off-by: Steven Rostedt Signed-off-by: Tyler Hicks --- fs/ecryptfs/keystore.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index 4725a07f003c..831c5f8529be 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -26,7 +26,6 @@ */ #include -#include #include #include #include -- GitLab From 04ec5f5c0022ee941615e304bc75853fe1bc94ba Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 8 Jul 2014 18:30:07 +0200 Subject: [PATCH 0005/5088] ecryptfs: remove unnecessary break after goto Signed-off-by: Fabian Frederick Cc: ecryptfs@vger.kernel.org Signed-off-by: Tyler Hicks --- fs/ecryptfs/keystore.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index 831c5f8529be..635e8e16a5b7 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -1845,7 +1845,6 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, "(Tag 11 not allowed by itself)\n"); rc = -EIO; goto out_wipe_list; - break; default: ecryptfs_printk(KERN_DEBUG, "No packet at offset [%zd] " "of the file header; hex value of " -- GitLab From 1d2ce978d160fa960f12d06bf84e45f47c141272 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 23 Jul 2014 17:10:44 -0300 Subject: [PATCH 0006/5088] x86, microcode, amd: Fix missing static declaration Make locally used variable static. Signed-off-by: Henrique de Moraes Holschuh Link: http://lkml.kernel.org/r/1406146251-8540-1-git-send-email-hmh@hmh.eng.br Signed-off-by: Borislav Petkov --- arch/x86/kernel/cpu/microcode/amd_early.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c index 617a9e284245..7aa1acc79789 100644 --- a/arch/x86/kernel/cpu/microcode/amd_early.c +++ b/arch/x86/kernel/cpu/microcode/amd_early.c @@ -27,7 +27,7 @@ static u32 ucode_new_rev; u8 amd_ucode_patch[PATCH_MAX_SIZE]; static u16 this_equiv_id; -struct cpio_data ucode_cpio; +static struct cpio_data ucode_cpio; /* * Microcode patch container file is prepended to the initrd in cpio format. -- GitLab From 05a5f76d033f413396bc48ce2f8651b5659bcd31 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 23 Jul 2014 17:10:45 -0300 Subject: [PATCH 0007/5088] x86, microcode, intel: Add missing static declarations gcc reports that a few declarations are missing. Fix two obvious ones. Signed-off-by: Henrique de Moraes Holschuh Link: http://lkml.kernel.org/r/1406146251-8540-1-git-send-email-hmh@hmh.eng.br Signed-off-by: Borislav Petkov --- arch/x86/kernel/cpu/microcode/intel_early.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/intel_early.c b/arch/x86/kernel/cpu/microcode/intel_early.c index 18f739129e72..b105c11c6f59 100644 --- a/arch/x86/kernel/cpu/microcode/intel_early.c +++ b/arch/x86/kernel/cpu/microcode/intel_early.c @@ -28,8 +28,8 @@ #include #include -unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT]; -struct mc_saved_data { +static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT]; +static struct mc_saved_data { unsigned int mc_saved_count; struct microcode_intel **mc_saved; } mc_saved_data; -- GitLab From f99b45c3c2aa6960b8d21bb200d144be48a0a783 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 23 Jul 2014 17:10:46 -0300 Subject: [PATCH 0008/5088] x86, microcode, intel: Fix typos Fix some typos. One of them was in a struct name, fortunately harmless because it happened on a "sizeof(struct foo*)" construction. Signed-off-by: Henrique de Moraes Holschuh Link: http://lkml.kernel.org/r/1406146251-8540-1-git-send-email-hmh@hmh.eng.br Signed-off-by: Borislav Petkov --- arch/x86/kernel/cpu/microcode/intel_early.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/intel_early.c b/arch/x86/kernel/cpu/microcode/intel_early.c index b105c11c6f59..b88343f7a3b3 100644 --- a/arch/x86/kernel/cpu/microcode/intel_early.c +++ b/arch/x86/kernel/cpu/microcode/intel_early.c @@ -415,7 +415,7 @@ static void __ref show_saved_mc(void) struct ucode_cpu_info uci; if (mc_saved_data.mc_saved_count == 0) { - pr_debug("no micorcode data saved.\n"); + pr_debug("no microcode data saved.\n"); return; } pr_debug("Total microcode saved: %d\n", mc_saved_data.mc_saved_count); @@ -506,7 +506,7 @@ int save_mc_for_early(u8 *mc) if (mc_saved && mc_saved_count) memcpy(mc_saved_tmp, mc_saved, - mc_saved_count * sizeof(struct mirocode_intel *)); + mc_saved_count * sizeof(struct microcode_intel *)); /* * Save the microcode patch mc in mc_save_tmp structure if it's a newer * version. @@ -526,7 +526,7 @@ int save_mc_for_early(u8 *mc) show_saved_mc(); /* - * Free old saved microcod data. + * Free old saved microcode data. */ if (mc_saved) { for (i = 0; i < mc_saved_count_init; i++) -- GitLab From 532ed3740c1ed1583ea3fa6de9410edf0d508563 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Thu, 24 Jul 2014 15:23:21 -0300 Subject: [PATCH 0009/5088] x86, microcode, intel: Rename apply_microcode and declare it static Rename apply_microcode() in microcode/intel.c to apply_microcode_intel(), and declare it as static. This is a cosmetic fix to silence a warning issued by sparse. Signed-off-by: Henrique de Moraes Holschuh Link: http://lkml.kernel.org/r/1406146251-8540-1-git-send-email-hmh@hmh.eng.br Signed-off-by: Borislav Petkov --- arch/x86/kernel/cpu/microcode/intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index a276fa75d9b5..c6826d1e8082 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -127,7 +127,7 @@ static int get_matching_mc(struct microcode_intel *mc_intel, int cpu) return get_matching_microcode(csig, cpf, mc_intel, crev); } -int apply_microcode(int cpu) +static int apply_microcode_intel(int cpu) { struct microcode_intel *mc_intel; struct ucode_cpu_info *uci; @@ -314,7 +314,7 @@ static struct microcode_ops microcode_intel_ops = { .request_microcode_user = request_microcode_user, .request_microcode_fw = request_microcode_fw, .collect_cpu_info = collect_cpu_info, - .apply_microcode = apply_microcode, + .apply_microcode = apply_microcode_intel, .microcode_fini_cpu = microcode_fini_cpu, }; -- GitLab From ebc14ddcc9454c02439b67f6536628289faaa26e Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 23 Jul 2014 17:10:49 -0300 Subject: [PATCH 0010/5088] x86, microcode, intel: Fix total_size computation According to the Intel SDM vol 3A (order code 253668-051US, June 2014), on section 9.11.1, page 9-28: "For microcode updates with a data size field equal to 00000000H, the size of the microcode update is 2048 bytes. The first 48 bytes contain the microcode update header. The remaining 2000 bytes contain encrypted data." "For microcode updates with a data size not equal to 00000000H, the total size field specifies the size of the microcode update." Up to 2002/2003, Intel used an "old format" for the microcode update containers that was always 2048 bytes in size. That old format did not have Data Size and Total Size fields, the quadwords at those positions in the microcode container header were "reserved". The microcode header of the "old format" microcode container has a hrdver of 0x01. You can hunt down an old copy of the Intel SDM to validate this through its order number (#243192). I found one from 1999 through a Google search. Sometime in 2002/2003 (AFAICT, for the Prescott processors), Intel documented a new format for the microcode containers and contributed in 2003 some code to the Linux kernel microcode driver implementing support for the new format. This new format has Data Size and Total Size fields, as well as the optional extended signature table. However, it reuses the same hrdver as the old format (0x01), and it can only be told apart from the old format by a non-zero Data Size field. In fact, the only reason we can even trust a Data Size of zero to mean that the microcode container is in the old format, is because Intel reatroatively promised that the old format would always have a zero there when they wrote the documentation for the _new_ format. This is a very old bug, dating back to 2003. It has been dormant ever since, as Intel seems to set all reserved fields to zero on the microcode updates they distribute: I could not find a public microcode update that would trigger this bug. Signed-off-by: Henrique de Moraes Holschuh Link: http://lkml.kernel.org/r/1406146251-8540-1-git-send-email-hmh@hmh.eng.br Signed-off-by: Borislav Petkov --- arch/x86/include/asm/microcode_intel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/microcode_intel.h b/arch/x86/include/asm/microcode_intel.h index 9067166409bf..bbe296e0bce1 100644 --- a/arch/x86/include/asm/microcode_intel.h +++ b/arch/x86/include/asm/microcode_intel.h @@ -43,7 +43,7 @@ struct extended_sigtable { #define DWSIZE (sizeof(u32)) #define get_totalsize(mc) \ - (((struct microcode_intel *)mc)->hdr.totalsize ? \ + (((struct microcode_intel *)mc)->hdr.datasize ? \ ((struct microcode_intel *)mc)->hdr.totalsize : \ DEFAULT_UCODE_TOTALSIZE) -- GitLab From 7d885749b6de2c9a1168d566e2380207b9177108 Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Fri, 25 Jul 2014 18:02:46 -0400 Subject: [PATCH 0011/5088] perf tools: Fix arm64 build error I'm seeing the following build error on arm64: In file included from util/event.c:3:0: util/event.h:95:17: error: 'PERF_REGS_MAX' undeclared here (not in a function) u64 cache_regs[PERF_REGS_MAX]; ^ This patch adds a PERF_REGS_MAX definition for arm64. Signed-off-by: Mark Salter Acked-by: Jean Pihet Cc: Ingo Molnar Cc: Jean Pihet Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1406325766-8085-1-git-send-email-msalter@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm64/include/perf_regs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/arch/arm64/include/perf_regs.h b/tools/perf/arch/arm64/include/perf_regs.h index e9441b9e2a30..1d3f39c3aa56 100644 --- a/tools/perf/arch/arm64/include/perf_regs.h +++ b/tools/perf/arch/arm64/include/perf_regs.h @@ -6,6 +6,8 @@ #include #define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1) +#define PERF_REGS_MAX PERF_REG_ARM64_MAX + #define PERF_REG_IP PERF_REG_ARM64_PC #define PERF_REG_SP PERF_REG_ARM64_SP -- GitLab From 5f1c4225f6bcb20cc004b271dc72b96d0da29e9e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Jul 2014 12:39:50 -0300 Subject: [PATCH 0012/5088] perf evlist: Don't run workload if not told to The perf_evlist__prepare_workload() method works by forking and then waiting on a fd that must be written to to allow the workload to be exec()ed. But if the tool calling it fails to, say, set up the events with which it wants to sample the workload for, it will not call perf_evlist__start_workload(), but even in this case the workload ended up running: [acme@zoo linux]$ trace /bin/echo workload ends up running, it should not... Couldn't mmap the events: Operation not permitted workload ends up running, it should not... [acme@zoo linux]$ So check if at least one byte was written before letting exec() be called. Now the expected behaviour: [acme@zoo linux]$ trace /bin/echo workload ends up running, it should not... Couldn't mmap the events: Operation not permitted [acme@zoo linux]$ Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-oh1ixo8m74rf295a05gfjw8b@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 814e954c1318..3b366c085021 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1061,6 +1061,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar } if (!evlist->workload.pid) { + int ret; + if (pipe_output) dup2(2, 1); @@ -1078,8 +1080,22 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar /* * Wait until the parent tells us to go. */ - if (read(go_pipe[0], &bf, 1) == -1) - perror("unable to read pipe"); + ret = read(go_pipe[0], &bf, 1); + /* + * The parent will ask for the execvp() to be performed by + * writing exactly one byte, in workload.cork_fd, usually via + * perf_evlist__start_workload(). + * + * For cancelling the workload without actuallin running it, + * the parent will just close workload.cork_fd, without writing + * anything, i.e. read will return zero and we just exit() + * here. + */ + if (ret != 1) { + if (ret == -1) + perror("unable to read pipe"); + exit(ret); + } execvp(argv[0], (char **)argv); -- GitLab From 972f393bc8870e236edbd2ea0150a8da85b709e2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 29 Jul 2014 10:21:58 -0300 Subject: [PATCH 0013/5088] perf symbols: Make sure --symfs usage includes the path separator Minchan reported that perf failed to load vmlinux if --symfs argument doesn't end with '/' character. Fix it by making sure that the '/' path separator is used when composing pathnames with a --symfs provided directory name. Reported-by: Minchan Kim Cc: David Ahern Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-8n4s6b6zvsez5ktanw006125@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 9 +++------ tools/perf/util/dso.c | 28 +++++++++++++--------------- tools/perf/util/symbol.c | 3 +-- tools/perf/util/symbol.h | 9 +++++++++ tools/perf/util/util.h | 16 ++++++++++++++++ 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 809b4c50beae..7745fec01a6b 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -899,10 +899,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) struct kcore_extract kce; bool delete_extract = false; - if (filename) { - snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", - symbol_conf.symfs, filename); - } + if (filename) + symbol__join_symfs(symfs_filename, filename); if (filename == NULL) { if (dso->has_build_id) { @@ -922,8 +920,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) * DSO is the same as when 'perf record' ran. */ filename = (char *)dso->long_name; - snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", - symbol_conf.symfs, filename); + symbol__join_symfs(symfs_filename, filename); free_filename = false; } diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 90d02c661dd4..bdafd306fb52 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -37,6 +37,7 @@ int dso__read_binary_type_filename(const struct dso *dso, { char build_id_hex[BUILD_ID_SIZE * 2 + 1]; int ret = 0; + size_t len; switch (type) { case DSO_BINARY_TYPE__DEBUGLINK: { @@ -60,26 +61,25 @@ int dso__read_binary_type_filename(const struct dso *dso, break; case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: - snprintf(filename, size, "%s/usr/lib/debug%s.debug", - symbol_conf.symfs, dso->long_name); + len = __symbol__join_symfs(filename, size, "/usr/lib/debug"); + snprintf(filename + len, size - len, "%s.debug", dso->long_name); break; case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: - snprintf(filename, size, "%s/usr/lib/debug%s", - symbol_conf.symfs, dso->long_name); + len = __symbol__join_symfs(filename, size, "/usr/lib/debug"); + snprintf(filename + len, size - len, "%s", dso->long_name); break; case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: { const char *last_slash; - size_t len; size_t dir_size; last_slash = dso->long_name + dso->long_name_len; while (last_slash != dso->long_name && *last_slash != '/') last_slash--; - len = scnprintf(filename, size, "%s", symbol_conf.symfs); + len = __symbol__join_symfs(filename, size, ""); dir_size = last_slash - dso->long_name + 2; if (dir_size > (size - len)) { ret = -1; @@ -100,26 +100,24 @@ int dso__read_binary_type_filename(const struct dso *dso, build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex); - snprintf(filename, size, - "%s/usr/lib/debug/.build-id/%.2s/%s.debug", - symbol_conf.symfs, build_id_hex, build_id_hex + 2); + len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/"); + snprintf(filename + len, size - len, "%.2s/%s.debug", + build_id_hex, build_id_hex + 2); break; case DSO_BINARY_TYPE__VMLINUX: case DSO_BINARY_TYPE__GUEST_VMLINUX: case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: - snprintf(filename, size, "%s%s", - symbol_conf.symfs, dso->long_name); + __symbol__join_symfs(filename, size, dso->long_name); break; case DSO_BINARY_TYPE__GUEST_KMODULE: - snprintf(filename, size, "%s%s%s", symbol_conf.symfs, - root_dir, dso->long_name); + path__join3(filename, size, symbol_conf.symfs, + root_dir, dso->long_name); break; case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: - snprintf(filename, size, "%s%s", symbol_conf.symfs, - dso->long_name); + __symbol__join_symfs(filename, size, dso->long_name); break; case DSO_BINARY_TYPE__KCORE: diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index eb06746b06b2..f134ec138934 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1468,8 +1468,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, if (vmlinux[0] == '/') snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); else - snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", - symbol_conf.symfs, vmlinux); + symbol__join_symfs(symfs_vmlinux, vmlinux); if (dso->kernel == DSO_TYPE_GUEST_KERNEL) symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index e7295e93cff9..196b29104276 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -13,6 +13,7 @@ #include #include "build-id.h" #include "event.h" +#include "util.h" #ifdef HAVE_LIBELF_SUPPORT #include @@ -143,6 +144,14 @@ struct symbol_conf { }; extern struct symbol_conf symbol_conf; + +static inline int __symbol__join_symfs(char *bf, size_t size, const char *path) +{ + return path__join(bf, size, symbol_conf.symfs, path); +} + +#define symbol__join_symfs(bf, path) __symbol__join_symfs(bf, sizeof(bf), path) + extern int vmlinux_path__nr_entries; extern char **vmlinux_path; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 66864364ccb4..38af77550c75 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -317,6 +318,21 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags); #define SRCLINE_UNKNOWN ((char *) "??:0") +static inline int path__join(char *bf, size_t size, + const char *path1, const char *path2) +{ + return scnprintf(bf, size, "%s%s%s", path1, path1[0] ? "/" : "", path2); +} + +static inline int path__join3(char *bf, size_t size, + const char *path1, const char *path2, + const char *path3) +{ + return scnprintf(bf, size, "%s%s%s%s%s", + path1, path1[0] ? "/" : "", + path2, path2[0] ? "/" : "", path3); +} + struct dso; char *get_srcline(struct dso *dso, unsigned long addr); -- GitLab From b048a24cc8f29dce1bad564aaeb8680020d3701c Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 31 Jul 2014 13:13:51 +0200 Subject: [PATCH 0014/5088] perf kvm stat: Properly show submicrosecond times For lots of exits the min time (and sometimes max) is 0 or 1. Lets increase the accurancy similar to what the average field alread does. Signed-off-by: Christian Borntraeger Acked-by: David Ahern Cc: David Ahern Cc: Jiri Olsa Cc: Paolo Bonzini Cc: kvm@vger.kernel.org Link: http://lkml.kernel.org/r/1406805231-10675-2-git-send-email-borntraeger@de.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 43367eb00510..fe92dfdeab46 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -592,8 +592,8 @@ static void print_result(struct perf_kvm_stat *kvm) pr_info("%9s ", "Samples%"); pr_info("%9s ", "Time%"); - pr_info("%10s ", "Min Time"); - pr_info("%10s ", "Max Time"); + pr_info("%11s ", "Min Time"); + pr_info("%11s ", "Max Time"); pr_info("%16s ", "Avg time"); pr_info("\n\n"); @@ -610,8 +610,8 @@ static void print_result(struct perf_kvm_stat *kvm) pr_info("%10llu ", (unsigned long long)ecount); pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); - pr_info("%8" PRIu64 "us ", min / 1000); - pr_info("%8" PRIu64 "us ", max / 1000); + pr_info("%9.2fus ", (double)min / 1e3); + pr_info("%9.2fus ", (double)max / 1e3); pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, kvm_event_rel_stddev(vcpu, event)); pr_info("\n"); -- GitLab From 83f45fc360c8e16a330474860ebda872d1384c8c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 09:10:18 +0200 Subject: [PATCH 0015/5088] drm: Don't grab an fb reference for the idr The current refcounting scheme is that the fb lookup idr also holds a reference. This works out nicely bacause thus far we've always explicitly cleaned up idr entries for framebuffers: - Userspace fbs get removed in the rmfb ioctl or when the drm file gets closed. - Kernel fbs (for fbdev emulation) get cleaned up by the driver code at module unload time. But now i915 also reconstructs the bios fbs for a smooth transition. And that fb is purely transitional and should get removed immmediately once all crtcs stop using it. Of course if the i915 fbdev code decides to reuse it as the main fbdev fb then it shouldn't be cleaned up, but in that case the fbdev code will grab it's own reference. The problem is now that we also want to register that takeover fb in the idr, so that userspace can do a smooth transition (animated maybe even!) itself. But currently we have no one who will clean up the idr reference once that fb isn't useful any more, and so essentially leak it. Fix this by no longer holding a full fb reference for the idr, but instead just have a weak reference using kref_get_unless_zero. But that requires us to synchronize and clean up with the idr and fb_lock in drm_framebuffer_free, so add that. It's a bit ugly that we have to unconditionally grab the fb_lock, but without that someone might creep through a race. This leak was caught by the fb leak check in drm_mode_config_cleanup. Originally the leak was introduced in commit 46f297fb83d4f9a6f6891964beb184664341a28b Author: Jesse Barnes Date: Fri Mar 7 08:57:48 2014 -0800 drm/i915: add plane_config fetching infrastructure v2 Cc: Jesse Barnes Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=77511 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 46 +++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index fa2be249999c..33ff631c8d23 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -515,9 +515,6 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, if (ret) goto out; - /* Grab the idr reference. */ - drm_framebuffer_reference(fb); - dev->mode_config.num_fb++; list_add(&fb->head, &dev->mode_config.fb_list); out: @@ -527,10 +524,34 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_framebuffer_init); +/* dev->mode_config.fb_lock must be held! */ +static void __drm_framebuffer_unregister(struct drm_device *dev, + struct drm_framebuffer *fb) +{ + mutex_lock(&dev->mode_config.idr_mutex); + idr_remove(&dev->mode_config.crtc_idr, fb->base.id); + mutex_unlock(&dev->mode_config.idr_mutex); + + fb->base.id = 0; +} + static void drm_framebuffer_free(struct kref *kref) { struct drm_framebuffer *fb = container_of(kref, struct drm_framebuffer, refcount); + struct drm_device *dev = fb->dev; + + /* + * The lookup idr holds a weak reference, which has not necessarily been + * removed at this point. Check for that. + */ + mutex_lock(&dev->mode_config.fb_lock); + if (fb->base.id) { + /* Mark fb as reaped and drop idr ref. */ + __drm_framebuffer_unregister(dev, fb); + } + mutex_unlock(&dev->mode_config.fb_lock); + fb->funcs->destroy(fb); } @@ -567,8 +588,10 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, mutex_lock(&dev->mode_config.fb_lock); fb = __drm_framebuffer_lookup(dev, id); - if (fb) - drm_framebuffer_reference(fb); + if (fb) { + if (!kref_get_unless_zero(&fb->refcount)) + fb = NULL; + } mutex_unlock(&dev->mode_config.fb_lock); return fb; @@ -612,19 +635,6 @@ static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) kref_put(&fb->refcount, drm_framebuffer_free_bug); } -/* dev->mode_config.fb_lock must be held! */ -static void __drm_framebuffer_unregister(struct drm_device *dev, - struct drm_framebuffer *fb) -{ - mutex_lock(&dev->mode_config.idr_mutex); - idr_remove(&dev->mode_config.crtc_idr, fb->base.id); - mutex_unlock(&dev->mode_config.idr_mutex); - - fb->base.id = 0; - - __drm_framebuffer_unreference(fb); -} - /** * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr * @fb: fb to unregister -- GitLab From ea6763c104c93acb6554659fe4a3c9e9328a4b51 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 11:36:38 +0200 Subject: [PATCH 0016/5088] video/fbdev: Always built-in video= cmdline parsing In drm/i915 we want to get at the video= cmdline modes even when we don't have fbdev support enabled, so that users can always override the kernel's initial mode selection. But that gives us a direct depency upon the parsing code in the fbdev subsystem. Since it's so little code just extract these 2 functions and always build them in. Whiel at it fix the checkpatch fail in this code. v2: Also move fb_mode_option. Spotted by the kbuild. v3: Review from Geert: - Keep the old copyright notice from fb_mem.c, although I have no idea what exactly applies. - Only compile this when needed. Cc: Geert Uytterhoeven Cc: Plagniol-Villard Cc: Tomi Valkeinen Cc: linux-fbdev@vger.kernel.org Signed-off-by: Daniel Vetter -- I prefer if we can merge this through drm-next since we'll use it there in follow-up patches. -Daniel --- drivers/video/fbdev/Kconfig | 4 + drivers/video/fbdev/core/Makefile | 1 + drivers/video/fbdev/core/fb_cmdline.c | 110 ++++++++++++++++++++++++++ drivers/video/fbdev/core/fbmem.c | 92 --------------------- drivers/video/fbdev/core/modedb.c | 3 - 5 files changed, 115 insertions(+), 95 deletions(-) create mode 100644 drivers/video/fbdev/core/fb_cmdline.c diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 59c98bfd5a8a..f1458c95a688 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -4,6 +4,7 @@ menuconfig FB tristate "Support for frame buffer devices" + select FB_CMDLINE ---help--- The frame buffer device provides an abstraction for the graphics hardware. It represents the frame buffer of some video hardware and @@ -52,6 +53,9 @@ config FIRMWARE_EDID combination with certain motherboards and monitors are known to suffer from this problem. +config FB_CMDLINE + bool + config FB_DDC tristate depends on FB diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile index fa306538dac2..67f28e20a892 100644 --- a/drivers/video/fbdev/core/Makefile +++ b/drivers/video/fbdev/core/Makefile @@ -1,4 +1,5 @@ obj-y += fb_notify.o +obj-$(CONFIG_FB_CMDLINE) += fb_cmdline.o obj-$(CONFIG_FB) += fb.o fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ modedb.o fbcvt.o diff --git a/drivers/video/fbdev/core/fb_cmdline.c b/drivers/video/fbdev/core/fb_cmdline.c new file mode 100644 index 000000000000..39509ccd92f1 --- /dev/null +++ b/drivers/video/fbdev/core/fb_cmdline.c @@ -0,0 +1,110 @@ +/* + * linux/drivers/video/fb_cmdline.c + * + * Copyright (C) 2014 Intel Corp + * Copyright (C) 1994 Martin Schaller + * + * 2001 - Documented with DocBook + * - Brad Douglas + * + * 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. + * + * Authors: + * Vetter + */ +#include +#include + +static char *video_options[FB_MAX] __read_mostly; +static int ofonly __read_mostly; + +const char *fb_mode_option; +EXPORT_SYMBOL_GPL(fb_mode_option); + +/** + * fb_get_options - get kernel boot parameters + * @name: framebuffer name as it would appear in + * the boot parameter line + * (video=:) + * @option: the option will be stored here + * + * NOTE: Needed to maintain backwards compatibility + */ +int fb_get_options(const char *name, char **option) +{ + char *opt, *options = NULL; + int retval = 0; + int name_len = strlen(name), i; + + if (name_len && ofonly && strncmp(name, "offb", 4)) + retval = 1; + + if (name_len && !retval) { + for (i = 0; i < FB_MAX; i++) { + if (video_options[i] == NULL) + continue; + if (!video_options[i][0]) + continue; + opt = video_options[i]; + if (!strncmp(name, opt, name_len) && + opt[name_len] == ':') + options = opt + name_len + 1; + } + } + /* No match, pass global option */ + if (!options && option && fb_mode_option) + options = kstrdup(fb_mode_option, GFP_KERNEL); + if (options && !strncmp(options, "off", 3)) + retval = 1; + + if (option) + *option = options; + + return retval; +} +EXPORT_SYMBOL(fb_get_options); + +/** + * video_setup - process command line options + * @options: string of options + * + * Process command line options for frame buffer subsystem. + * + * NOTE: This function is a __setup and __init function. + * It only stores the options. Drivers have to call + * fb_get_options() as necessary. + * + * Returns zero. + * + */ +static int __init video_setup(char *options) +{ + int i, global = 0; + + if (!options || !*options) + global = 1; + + if (!global && !strncmp(options, "ofonly", 6)) { + ofonly = 1; + global = 1; + } + + if (!global && !strchr(options, ':')) { + fb_mode_option = options; + global = 1; + } + + if (!global) { + for (i = 0; i < FB_MAX; i++) { + if (video_options[i] == NULL) { + video_options[i] = options; + break; + } + } + } + + return 1; +} +__setup("video=", video_setup); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index b5e85f6c1c26..0705d8883ede 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1908,96 +1908,4 @@ int fb_new_modelist(struct fb_info *info) return err; } -static char *video_options[FB_MAX] __read_mostly; -static int ofonly __read_mostly; - -/** - * fb_get_options - get kernel boot parameters - * @name: framebuffer name as it would appear in - * the boot parameter line - * (video=:) - * @option: the option will be stored here - * - * NOTE: Needed to maintain backwards compatibility - */ -int fb_get_options(const char *name, char **option) -{ - char *opt, *options = NULL; - int retval = 0; - int name_len = strlen(name), i; - - if (name_len && ofonly && strncmp(name, "offb", 4)) - retval = 1; - - if (name_len && !retval) { - for (i = 0; i < FB_MAX; i++) { - if (video_options[i] == NULL) - continue; - if (!video_options[i][0]) - continue; - opt = video_options[i]; - if (!strncmp(name, opt, name_len) && - opt[name_len] == ':') - options = opt + name_len + 1; - } - } - /* No match, pass global option */ - if (!options && option && fb_mode_option) - options = kstrdup(fb_mode_option, GFP_KERNEL); - if (options && !strncmp(options, "off", 3)) - retval = 1; - - if (option) - *option = options; - - return retval; -} -EXPORT_SYMBOL(fb_get_options); - -#ifndef MODULE -/** - * video_setup - process command line options - * @options: string of options - * - * Process command line options for frame buffer subsystem. - * - * NOTE: This function is a __setup and __init function. - * It only stores the options. Drivers have to call - * fb_get_options() as necessary. - * - * Returns zero. - * - */ -static int __init video_setup(char *options) -{ - int i, global = 0; - - if (!options || !*options) - global = 1; - - if (!global && !strncmp(options, "ofonly", 6)) { - ofonly = 1; - global = 1; - } - - if (!global && !strchr(options, ':')) { - fb_mode_option = options; - global = 1; - } - - if (!global) { - for (i = 0; i < FB_MAX; i++) { - if (video_options[i] == NULL) { - video_options[i] = options; - break; - } - - } - } - - return 1; -} -__setup("video=", video_setup); -#endif - MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index a9a907c440d7..388f7971494b 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -29,9 +29,6 @@ #define DPRINTK(fmt, args...) #endif -const char *fb_mode_option; -EXPORT_SYMBOL_GPL(fb_mode_option); - /* * Standard video mode definitions (taken from XFree86) */ -- GitLab From eaf99c749d43ae74ac7ffece5512f3c73f01dfd2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 6 Aug 2014 10:08:32 +0200 Subject: [PATCH 0017/5088] drm: Perform cmdline mode parsing during connector initialisation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i915.ko has a custom fbdev initialisation routine that aims to preserve the current mode set by the BIOS, unless overruled by the user. The user's wishes are determined by what, if any, mode is specified on the command line (via the video= parameter). However, that command line mode is first parsed by drm_fb_helper_initial_config() which is called after i915.ko's custom initial_config() as a fallback method. So in order for us to honour it, we need to move the cmdline parser earlier. If we perform the connector cmdline parsing as soon as we initialise the connector, that cmdline mode and forced status is then available even if the fbdev helper is not compiled in or never called. We also then expose the cmdline user mode in the connector mode lists. v2: Rebase after connector->name upheaval. v3: Adapt mga200 to look for the cmdline mode in the new place. Nicely simplifies things while at that. v4: Fix checkpatch. v5: Select FB_CMDLINE to adapt to the changed fbdev patch. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=73154 Signed-off-by: Chris Wilson (v2) Cc: Jesse Barnes Cc: Ville Syrjälä Cc: Daniel Vetter Reviewed-by: Jesse Barnes (v2) Cc: dri-devel@lists.freedesktop.org Cc: Julia Lemire Cc: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/drm_crtc.c | 55 ++++++++++++++++++++++ drivers/gpu/drm/drm_fb_helper.c | 64 ++------------------------ drivers/gpu/drm/drm_modes.c | 1 + drivers/gpu/drm/drm_probe_helper.c | 17 +++++++ drivers/gpu/drm/mgag200/mgag200_mode.c | 21 ++------- include/drm/drm_crtc.h | 1 + include/drm/drm_fb_helper.h | 1 - 8 files changed, 83 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 31894c8c1773..367f5dd23291 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -8,6 +8,7 @@ menuconfig DRM tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU && HAS_DMA select HDMI + select FB_CMDLINE select I2C select I2C_ALGOBIT select DMA_SHARED_BUFFER diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 33ff631c8d23..66d3bfb8d264 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -862,6 +862,59 @@ static void drm_mode_remove(struct drm_connector *connector, drm_mode_destroy(connector->dev, mode); } +/** + * drm_connector_get_cmdline_mode - reads the user's cmdline mode + * @connector: connector to quwery + * @mode: returned mode + * + * The kernel supports per-connector configration of its consoles through + * use of the video= parameter. This function parses that option and + * extracts the user's specified mode (or enable/disable status) for a + * particular connector. This is typically only used during the early fbdev + * setup. + */ +static void drm_connector_get_cmdline_mode(struct drm_connector *connector) +{ + struct drm_cmdline_mode *mode = &connector->cmdline_mode; + char *option = NULL; + + if (fb_get_options(connector->name, &option)) + return; + + if (!drm_mode_parse_command_line_for_connector(option, + connector, + mode)) + return; + + if (mode->force) { + const char *s; + + switch (mode->force) { + case DRM_FORCE_OFF: + s = "OFF"; + break; + case DRM_FORCE_ON_DIGITAL: + s = "ON - dig"; + break; + default: + case DRM_FORCE_ON: + s = "ON"; + break; + } + + DRM_INFO("forcing %s connector %s\n", connector->name, s); + connector->force = mode->force; + } + + DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", + connector->name, + mode->xres, mode->yres, + mode->refresh_specified ? mode->refresh : 60, + mode->rb ? " reduced blanking" : "", + mode->margins ? " with margins" : "", + mode->interlace ? " interlaced" : ""); +} + /** * drm_connector_init - Init a preallocated connector * @dev: DRM device @@ -914,6 +967,8 @@ int drm_connector_init(struct drm_device *dev, connector->edid_blob_ptr = NULL; connector->status = connector_status_unknown; + drm_connector_get_cmdline_mode(connector); + list_add_tail(&connector->head, &dev->mode_config.connector_list); dev->mode_config.num_connector++; diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3144db9dc0f1..3a6b6635e3f5 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -171,60 +171,6 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, } EXPORT_SYMBOL(drm_fb_helper_remove_one_connector); -static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) -{ - struct drm_fb_helper_connector *fb_helper_conn; - int i; - - for (i = 0; i < fb_helper->connector_count; i++) { - struct drm_cmdline_mode *mode; - struct drm_connector *connector; - char *option = NULL; - - fb_helper_conn = fb_helper->connector_info[i]; - connector = fb_helper_conn->connector; - mode = &fb_helper_conn->cmdline_mode; - - /* do something on return - turn off connector maybe */ - if (fb_get_options(connector->name, &option)) - continue; - - if (drm_mode_parse_command_line_for_connector(option, - connector, - mode)) { - if (mode->force) { - const char *s; - switch (mode->force) { - case DRM_FORCE_OFF: - s = "OFF"; - break; - case DRM_FORCE_ON_DIGITAL: - s = "ON - dig"; - break; - default: - case DRM_FORCE_ON: - s = "ON"; - break; - } - - DRM_INFO("forcing %s connector %s\n", - connector->name, s); - connector->force = mode->force; - } - - DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", - connector->name, - mode->xres, mode->yres, - mode->refresh_specified ? mode->refresh : 60, - mode->rb ? " reduced blanking" : "", - mode->margins ? " with margins" : "", - mode->interlace ? " interlaced" : ""); - } - - } - return 0; -} - static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) { uint16_t *r_base, *g_base, *b_base; @@ -1013,7 +959,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; struct drm_cmdline_mode *cmdline_mode; - cmdline_mode = &fb_helper_conn->cmdline_mode; + cmdline_mode = &fb_helper_conn->connector->cmdline_mode; if (cmdline_mode->bpp_specified) { switch (cmdline_mode->bpp) { @@ -1260,9 +1206,7 @@ EXPORT_SYMBOL(drm_has_preferred_mode); static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) { - struct drm_cmdline_mode *cmdline_mode; - cmdline_mode = &fb_connector->cmdline_mode; - return cmdline_mode->specified; + return fb_connector->connector->cmdline_mode.specified; } struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, @@ -1272,7 +1216,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f struct drm_display_mode *mode = NULL; bool prefer_non_interlace; - cmdline_mode = &fb_helper_conn->cmdline_mode; + cmdline_mode = &fb_helper_conn->connector->cmdline_mode; if (cmdline_mode->specified == false) return mode; @@ -1657,8 +1601,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) struct drm_device *dev = fb_helper->dev; int count = 0; - drm_fb_helper_parse_command_line(fb_helper); - mutex_lock(&dev->mode_config.mutex); count = drm_fb_helper_probe_connector_modes(fb_helper, dev->mode_config.max_width, diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index bedf1894e17e..d1b7d2006529 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1259,6 +1259,7 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev, if (!mode) return NULL; + mode->type |= DRM_MODE_TYPE_USERDEF; drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); return mode; } diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index db7d250f7ac7..6857e9ad6339 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -82,6 +82,22 @@ static void drm_mode_validate_flag(struct drm_connector *connector, return; } +static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector) +{ + struct drm_display_mode *mode; + + if (!connector->cmdline_mode.specified) + return 0; + + mode = drm_mode_create_from_cmdline_mode(connector->dev, + &connector->cmdline_mode); + if (mode == NULL) + return 0; + + drm_mode_probed_add(connector, mode); + return 1; +} + static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, uint32_t maxX, uint32_t maxY, bool merge_type_bits) { @@ -141,6 +157,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect if (count == 0 && connector->status == connector_status_connected) count = drm_add_modes_noedid(connector, 1024, 768); + count += drm_helper_probe_add_cmdline_mode(connector); if (count == 0) goto prune; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 45f04dea0ac2..83485ab81ce8 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1483,11 +1483,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector, { struct drm_device *dev = connector->dev; struct mga_device *mdev = (struct mga_device*)dev->dev_private; - struct mga_fbdev *mfbdev = mdev->mfbdev; - struct drm_fb_helper *fb_helper = &mfbdev->helper; - struct drm_fb_helper_connector *fb_helper_conn = NULL; int bpp = 32; - int i = 0; if (IS_G200_SE(mdev)) { if (mdev->unique_rev_id == 0x01) { @@ -1537,21 +1533,14 @@ static int mga_vga_mode_valid(struct drm_connector *connector, } /* Validate the mode input by the user */ - for (i = 0; i < fb_helper->connector_count; i++) { - if (fb_helper->connector_info[i]->connector == connector) { - /* Found the helper for this connector */ - fb_helper_conn = fb_helper->connector_info[i]; - if (fb_helper_conn->cmdline_mode.specified) { - if (fb_helper_conn->cmdline_mode.bpp_specified) { - bpp = fb_helper_conn->cmdline_mode.bpp; - } - } - } + if (connector->cmdline_mode.specified) { + if (connector->cmdline_mode.bpp_specified) + bpp = connector->cmdline_mode.bpp; } if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->mc.vram_size) { - if (fb_helper_conn) - fb_helper_conn->cmdline_mode.specified = false; + if (connector->cmdline_mode.specified) + connector->cmdline_mode.specified = false; return MODE_BAD; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f1105d0da059..c530b4920a09 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -548,6 +548,7 @@ struct drm_connector { void *helper_private; /* forced on connector */ + struct drm_cmdline_mode cmdline_mode; enum drm_connector_force force; bool override_edid; uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index bfd329d613c4..f4ad254e3488 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -77,7 +77,6 @@ struct drm_fb_helper_funcs { struct drm_fb_helper_connector { struct drm_connector *connector; - struct drm_cmdline_mode cmdline_mode; }; struct drm_fb_helper { -- GitLab From ddde43711fdde505ac413102faa2352704cd858a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:02:50 +0300 Subject: [PATCH 0018/5088] drm: Warn when leaking flip events on close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Warn when there are events on the file_priv->event_list just before file_priv gets freed. This can occur if the driver doesn't clean up pending page flip events in ->preclose(). Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_fops.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 8f91062db5b6..0fa4dadac4c6 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -529,6 +529,8 @@ int drm_release(struct inode *inode, struct file *filp) if (drm_core_check_feature(dev, DRIVER_PRIME)) drm_prime_destroy_file_private(&file_priv->prime); + WARN_ON(!list_empty(&file_priv->event_list)); + put_pid(file_priv->pid); kfree(file_priv); -- GitLab From e6ae8687a87b1fe5c25e824c8ad300f5587eb622 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 6 Aug 2014 13:16:59 -0400 Subject: [PATCH 0019/5088] drm: idiot-proof vblank After spending slightly more time than I'd care to admit debugging the various and presumably spectacular way things fail when you pass too low a value to drm_vblank_init() (thanks console-lock for not letting me see the carnage!), I decided it might be a good idea to add some sanity checking. Signed-off-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 0de123afdb34..6f16a104d6d0 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -730,6 +730,8 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp); */ u32 drm_vblank_count(struct drm_device *dev, int crtc) { + if (WARN_ON(crtc >= dev->num_crtcs)) + return 0; return atomic_read(&dev->vblank[crtc].count); } EXPORT_SYMBOL(drm_vblank_count); @@ -752,6 +754,9 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, { u32 cur_vblank; + if (WARN_ON(crtc >= dev->num_crtcs)) + return 0; + /* Read timestamp from slot of _vblank_time ringbuffer * that corresponds to current vblank count. Retry if * count has incremented during readout. This works like @@ -927,6 +932,9 @@ int drm_vblank_get(struct drm_device *dev, int crtc) unsigned long irqflags; int ret = 0; + if (WARN_ON(crtc >= dev->num_crtcs)) + return -EINVAL; + spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) { @@ -975,6 +983,9 @@ void drm_vblank_put(struct drm_device *dev, int crtc) { BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0); + if (WARN_ON(crtc >= dev->num_crtcs)) + return; + /* Last user schedules interrupt disable */ if (atomic_dec_and_test(&dev->vblank[crtc].refcount) && (drm_vblank_offdelay > 0)) @@ -1019,6 +1030,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc) unsigned long irqflags; unsigned int seq; + if (WARN_ON(crtc >= dev->num_crtcs)) + return; + spin_lock_irqsave(&dev->vbl_lock, irqflags); vblank_disable_and_save(dev, crtc); wake_up(&dev->vblank[crtc].queue); @@ -1078,6 +1092,9 @@ void drm_vblank_on(struct drm_device *dev, int crtc) { unsigned long irqflags; + if (WARN_ON(crtc >= dev->num_crtcs)) + return; + spin_lock_irqsave(&dev->vbl_lock, irqflags); /* re-enable interrupts if there's are users left */ if (atomic_read(&dev->vblank[crtc].refcount) != 0) @@ -1131,6 +1148,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) /* vblank is not initialized (IRQ not installed ?), or has been freed */ if (!dev->num_crtcs) return; + + if (WARN_ON(crtc >= dev->num_crtcs)) + return; + /* * To avoid all the problems that might happen if interrupts * were enabled/disabled around or between these calls, we just @@ -1439,6 +1460,9 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) if (!dev->num_crtcs) return false; + if (WARN_ON(crtc >= dev->num_crtcs)) + return false; + /* Need timestamp lock to prevent concurrent execution with * vblank enable/disable, as this would cause inconsistent * or corrupted timestamps and vblank counts. -- GitLab From 7ffd7a68511c710b84db3548a1997fd2625f580a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:44 +0300 Subject: [PATCH 0020/5088] drm: Always reject drm_vblank_get() after drm_vblank_off() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure drm_vblank_get() never succeeds when called between drm_vblank_off() and drm_vblank_on(). Borrow a trick from the old drm_vblank_{pre,post}_modeset() functions and just bump the refcount in drm_vblank_off() and drop it in drm_vblank_on(). When drm_vblank_get() encounters a >0 refcount and the vblank interrupt is already disabled it will simply return -EINVAL. Hopefully the use of inmodeset won't conflict badly with drm_vblank_{pre,post}_modeset(). For i915 there's a window between drm_vblank_off() and marking the crtc as inactive where the current code still allows drm_vblank_get(). v2: Describe what drm_vblank_get() does to explain how a simple refcount bump manages to fix things (Daniel) Reviewed-by: Matt Roper Reviewed-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 0de123afdb34..b16a63622bad 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1039,6 +1039,15 @@ void drm_vblank_off(struct drm_device *dev, int crtc) } spin_unlock(&dev->event_lock); + /* + * Prevent subsequent drm_vblank_get() from re-enabling + * the vblank interrupt by bumping the refcount. + */ + if (!dev->vblank[crtc].inmodeset) { + atomic_inc(&dev->vblank[crtc].refcount); + dev->vblank[crtc].inmodeset = 1; + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } EXPORT_SYMBOL(drm_vblank_off); @@ -1079,6 +1088,11 @@ void drm_vblank_on(struct drm_device *dev, int crtc) unsigned long irqflags; spin_lock_irqsave(&dev->vbl_lock, irqflags); + /* Drop our private "prevent drm_vblank_get" refcount */ + if (dev->vblank[crtc].inmodeset) { + atomic_dec(&dev->vblank[crtc].refcount); + dev->vblank[crtc].inmodeset = 0; + } /* re-enable interrupts if there's are users left */ if (atomic_read(&dev->vblank[crtc].refcount) != 0) WARN_ON(drm_vblank_enable(dev, crtc)); -- GitLab From 08c71e5e817a956389af5da5e99ab3e26d5c673d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:45 +0300 Subject: [PATCH 0021/5088] drm/i915: Warn if drm_vblank_get() still works after drm_vblank_off() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Drop the drm_vblank_off() (Daniel) Use drm_crtc_vblank_{get,put}() Reviewed-by: Matt Roper Reviewed-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 99eb7cad62a8..8f6b932d8e79 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1341,6 +1341,12 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv, } } +static void assert_vblank_disabled(struct drm_crtc *crtc) +{ + if (WARN_ON(drm_crtc_vblank_get(crtc) == 0)) + drm_crtc_vblank_put(crtc); +} + static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) { u32 val; @@ -3905,6 +3911,8 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; + assert_vblank_disabled(crtc); + drm_vblank_on(dev, pipe); intel_enable_primary_hw_plane(dev_priv, plane, pipe); @@ -3954,6 +3962,8 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe)); drm_vblank_off(dev, pipe); + + assert_vblank_disabled(crtc); } static void ironlake_crtc_enable(struct drm_crtc *crtc) -- GitLab From 844b03f27739135fe1fed2fef06da0ffc4c7a081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:46 +0300 Subject: [PATCH 0022/5088] drm: Don't clear vblank timestamps when vblank interrupt is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clearing the timestamps causes us to send zeroed timestamps to userspace if they get sent out in response to the drm_vblank_off(). It's better to send the very latest timestamp and count instead. Testcase: igt/kms_flip/modeset-vs-vblank-race Reviewed-by: Matt Roper Reviewed-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index b16a63622bad..65d2da9b604b 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -55,14 +55,6 @@ */ #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 -/* - * Clear vblank timestamp buffer for a crtc. - */ -static void clear_vblank_timestamps(struct drm_device *dev, int crtc) -{ - memset(dev->vblank[crtc].time, 0, sizeof(dev->vblank[crtc].time)); -} - /* * Disable vblank irq's on crtc, make sure that last vblank count * of hardware and corresponding consistent software vblank counter @@ -131,9 +123,6 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) smp_mb__after_atomic(); } - /* Invalidate all timestamps while vblank irq's are off. */ - clear_vblank_timestamps(dev, crtc); - spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); } -- GitLab From 13b030af54a5e307cbcccdf5479873fbc4b7f185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:47 +0300 Subject: [PATCH 0023/5088] drm: Move drm_update_vblank_count() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move drm_update_vblank_count() to avoid forward a declaration. No functional change. Reviewed-by: Matt Roper Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 128 +++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 65d2da9b604b..af965174b083 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -55,6 +55,70 @@ */ #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 +/** + * drm_update_vblank_count - update the master vblank counter + * @dev: DRM device + * @crtc: counter to update + * + * Call back into the driver to update the appropriate vblank counter + * (specified by @crtc). Deal with wraparound, if it occurred, and + * update the last read value so we can deal with wraparound on the next + * call if necessary. + * + * Only necessary when going from off->on, to account for frames we + * didn't get an interrupt for. + * + * Note: caller must hold dev->vbl_lock since this reads & writes + * device vblank fields. + */ +static void drm_update_vblank_count(struct drm_device *dev, int crtc) +{ + u32 cur_vblank, diff, tslot, rc; + struct timeval t_vblank; + + /* + * Interrupts were disabled prior to this call, so deal with counter + * wrap if needed. + * NOTE! It's possible we lost a full dev->max_vblank_count events + * here if the register is small or we had vblank interrupts off for + * a long time. + * + * We repeat the hardware vblank counter & timestamp query until + * we get consistent results. This to prevent races between gpu + * updating its hardware counter while we are retrieving the + * corresponding vblank timestamp. + */ + do { + cur_vblank = dev->driver->get_vblank_counter(dev, crtc); + rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); + } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); + + /* Deal with counter wrap */ + diff = cur_vblank - dev->vblank[crtc].last; + if (cur_vblank < dev->vblank[crtc].last) { + diff += dev->max_vblank_count; + + DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", + crtc, dev->vblank[crtc].last, cur_vblank, diff); + } + + DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", + crtc, diff); + + /* Reinitialize corresponding vblank timestamp if high-precision query + * available. Skip this step if query unsupported or failed. Will + * reinitialize delayed at next vblank interrupt in that case. + */ + if (rc) { + tslot = atomic_read(&dev->vblank[crtc].count) + diff; + vblanktimestamp(dev, crtc, tslot) = t_vblank; + } + + smp_mb__before_atomic(); + atomic_add(diff, &dev->vblank[crtc].count); + smp_mb__after_atomic(); +} + /* * Disable vblank irq's on crtc, make sure that last vblank count * of hardware and corresponding consistent software vblank counter @@ -798,70 +862,6 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc, } EXPORT_SYMBOL(drm_send_vblank_event); -/** - * drm_update_vblank_count - update the master vblank counter - * @dev: DRM device - * @crtc: counter to update - * - * Call back into the driver to update the appropriate vblank counter - * (specified by @crtc). Deal with wraparound, if it occurred, and - * update the last read value so we can deal with wraparound on the next - * call if necessary. - * - * Only necessary when going from off->on, to account for frames we - * didn't get an interrupt for. - * - * Note: caller must hold dev->vbl_lock since this reads & writes - * device vblank fields. - */ -static void drm_update_vblank_count(struct drm_device *dev, int crtc) -{ - u32 cur_vblank, diff, tslot, rc; - struct timeval t_vblank; - - /* - * Interrupts were disabled prior to this call, so deal with counter - * wrap if needed. - * NOTE! It's possible we lost a full dev->max_vblank_count events - * here if the register is small or we had vblank interrupts off for - * a long time. - * - * We repeat the hardware vblank counter & timestamp query until - * we get consistent results. This to prevent races between gpu - * updating its hardware counter while we are retrieving the - * corresponding vblank timestamp. - */ - do { - cur_vblank = dev->driver->get_vblank_counter(dev, crtc); - rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); - } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); - - /* Deal with counter wrap */ - diff = cur_vblank - dev->vblank[crtc].last; - if (cur_vblank < dev->vblank[crtc].last) { - diff += dev->max_vblank_count; - - DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", - crtc, dev->vblank[crtc].last, cur_vblank, diff); - } - - DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", - crtc, diff); - - /* Reinitialize corresponding vblank timestamp if high-precision query - * available. Skip this step if query unsupported or failed. Will - * reinitialize delayed at next vblank interrupt in that case. - */ - if (rc) { - tslot = atomic_read(&dev->vblank[crtc].count) + diff; - vblanktimestamp(dev, crtc, tslot) = t_vblank; - } - - smp_mb__before_atomic(); - atomic_add(diff, &dev->vblank[crtc].count); - smp_mb__after_atomic(); -} - /** * drm_vblank_enable - enable the vblank interrupt on a CRTC * @dev: DRM device -- GitLab From 812e7465a7decf3cca0b5f71977a25eecd9626a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:48 +0300 Subject: [PATCH 0024/5088] drm: Have the vblank counter account for the time between vblank irq disable and drm_vblank_off() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the vblank irq has already been disabled (via the disable timer) when we call drm_vblank_off() sample the counter and timestamp one last time. This will make the sure that the user space visible counter will account for time between vblank irq disable and drm_vblank_off(). Reviewed-by: Matt Roper Reviewed-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index af965174b083..1f86f6c6ecc6 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -140,6 +140,19 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) */ spin_lock_irqsave(&dev->vblank_time_lock, irqflags); + /* + * If the vblank interrupt was already disbled update the count + * and timestamp to maintain the appearance that the counter + * has been ticking all along until this time. This makes the + * count account for the entire time between drm_vblank_on() and + * drm_vblank_off(). + */ + if (!dev->vblank[crtc].enabled) { + drm_update_vblank_count(dev, crtc); + spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); + return; + } + dev->driver->disable_vblank(dev, crtc); dev->vblank[crtc].enabled = false; -- GitLab From f8ad028cc033f75fc479ca1c30e2ea4ba56e5269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:49 +0300 Subject: [PATCH 0025/5088] drm: Avoid random vblank counter jumps if the hardware counter has been reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When drm_vblank_on() is called the hardware vblank counter may have been reset, so we can't trust that the old values sampled prior to drm_vblank_off() have anything to do with the new values. So update the .last count in drm_vblank_on() to make the first drm_vblank_enable() consider that as the reference point. This will correct the user space visible counter to account for the time between drm_vblank_on() and the first drm_vblank_enable() calls. For extra safety subtract one from the .last count in drm_vblank_on() to make sure that user space will never see the same counter value before and after modeset. Reviewed-by: Matt Roper Reviewed-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 1f86f6c6ecc6..fc1525a499d9 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1095,6 +1095,18 @@ void drm_vblank_on(struct drm_device *dev, int crtc) atomic_dec(&dev->vblank[crtc].refcount); dev->vblank[crtc].inmodeset = 0; } + + /* + * sample the current counter to avoid random jumps + * when drm_vblank_enable() applies the diff + * + * -1 to make sure user will never see the same + * vblank counter value before and after a modeset + */ + dev->vblank[crtc].last = + (dev->driver->get_vblank_counter(dev, crtc) - 1) & + dev->max_vblank_count; + /* re-enable interrupts if there's are users left */ if (atomic_read(&dev->vblank[crtc].refcount) != 0) WARN_ON(drm_vblank_enable(dev, crtc)); -- GitLab From 8a51d5bef07f1c8c59de20089fb27ea39d395f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:50 +0300 Subject: [PATCH 0026/5088] drm: Reduce the amount of dev->vblank[crtc] in the code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare a local struct drm_vblank_crtc * and use that instead of having to do dig it out via 'dev->vblank[crtc]' everywhere. Performed with the following coccinelle incantation, and a few manual whitespace cleanups: @@ identifier func,member; expression num_crtcs; struct drm_device *dev; unsigned int crtc; @@ func (...) { + struct drm_vblank_crtc *vblank; ... if (crtc >= num_crtcs) return ...; + vblank = &dev->vblank[crtc]; <+... ( - dev->vblank[crtc].member + vblank->member | - &(dev->vblank[crtc]) + vblank ) ...+> } @@ struct drm_device *dev; int crtc; identifier member; expression num_crtcs; @@ for (crtc = 0; crtc < num_crtcs; crtc++) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; + <+... ( - dev->vblank[crtc].member + vblank->member | - &(dev->vblank[crtc]) + vblank ) ...+> } @@ identifier func,member; @@ func (struct drm_device *dev, int crtc, ...) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; <+... ( - dev->vblank[crtc].member + vblank->member | - &(dev->vblank[crtc]) + vblank ) ...+> } v2: Rebased Reviewed-by: Matt Roper Reviewed-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 134 ++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index fc1525a499d9..b4460bf0e0e4 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -73,6 +73,7 @@ */ static void drm_update_vblank_count(struct drm_device *dev, int crtc) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; u32 cur_vblank, diff, tslot, rc; struct timeval t_vblank; @@ -94,12 +95,12 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); /* Deal with counter wrap */ - diff = cur_vblank - dev->vblank[crtc].last; - if (cur_vblank < dev->vblank[crtc].last) { + diff = cur_vblank - vblank->last; + if (cur_vblank < vblank->last) { diff += dev->max_vblank_count; DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", - crtc, dev->vblank[crtc].last, cur_vblank, diff); + crtc, vblank->last, cur_vblank, diff); } DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", @@ -110,12 +111,12 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) * reinitialize delayed at next vblank interrupt in that case. */ if (rc) { - tslot = atomic_read(&dev->vblank[crtc].count) + diff; + tslot = atomic_read(&vblank->count) + diff; vblanktimestamp(dev, crtc, tslot) = t_vblank; } smp_mb__before_atomic(); - atomic_add(diff, &dev->vblank[crtc].count); + atomic_add(diff, &vblank->count); smp_mb__after_atomic(); } @@ -127,6 +128,7 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) */ static void vblank_disable_and_save(struct drm_device *dev, int crtc) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; unsigned long irqflags; u32 vblcount; s64 diff_ns; @@ -147,14 +149,14 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) * count account for the entire time between drm_vblank_on() and * drm_vblank_off(). */ - if (!dev->vblank[crtc].enabled) { + if (!vblank->enabled) { drm_update_vblank_count(dev, crtc); spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); return; } dev->driver->disable_vblank(dev, crtc); - dev->vblank[crtc].enabled = false; + vblank->enabled = false; /* No further vblank irq's will be processed after * this point. Get current hardware vblank count and @@ -169,9 +171,9 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) * delayed gpu counter increment. */ do { - dev->vblank[crtc].last = dev->driver->get_vblank_counter(dev, crtc); + vblank->last = dev->driver->get_vblank_counter(dev, crtc); vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); - } while (dev->vblank[crtc].last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc); + } while (vblank->last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc); if (!count) vblrc = 0; @@ -179,7 +181,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) /* Compute time difference to stored timestamp of last vblank * as updated by last invocation of drm_handle_vblank() in vblank irq. */ - vblcount = atomic_read(&dev->vblank[crtc].count); + vblcount = atomic_read(&vblank->count); diff_ns = timeval_to_ns(&tvblank) - timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); @@ -196,7 +198,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) * hope for the best. */ if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) { - atomic_inc(&dev->vblank[crtc].count); + atomic_inc(&vblank->count); smp_mb__after_atomic(); } @@ -236,8 +238,10 @@ void drm_vblank_cleanup(struct drm_device *dev) return; for (crtc = 0; crtc < dev->num_crtcs; crtc++) { - del_timer_sync(&dev->vblank[crtc].disable_timer); - vblank_disable_fn((unsigned long)&dev->vblank[crtc]); + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; + + del_timer_sync(&vblank->disable_timer); + vblank_disable_fn((unsigned long)vblank); } kfree(dev->vblank); @@ -270,11 +274,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) goto err; for (i = 0; i < num_crtcs; i++) { - dev->vblank[i].dev = dev; - dev->vblank[i].crtc = i; - init_waitqueue_head(&dev->vblank[i].queue); - setup_timer(&dev->vblank[i].disable_timer, vblank_disable_fn, - (unsigned long)&dev->vblank[i]); + struct drm_vblank_crtc *vblank = &dev->vblank[i]; + + vblank->dev = dev; + vblank->crtc = i; + init_waitqueue_head(&vblank->queue); + setup_timer(&vblank->disable_timer, vblank_disable_fn, + (unsigned long)vblank); } DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); @@ -426,9 +432,11 @@ int drm_irq_uninstall(struct drm_device *dev) if (dev->num_crtcs) { spin_lock_irqsave(&dev->vbl_lock, irqflags); for (i = 0; i < dev->num_crtcs; i++) { - wake_up(&dev->vblank[i].queue); - dev->vblank[i].enabled = false; - dev->vblank[i].last = + struct drm_vblank_crtc *vblank = &dev->vblank[i]; + + wake_up(&vblank->queue); + vblank->enabled = false; + vblank->last = dev->driver->get_vblank_counter(dev, i); } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); @@ -796,7 +804,9 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp); */ u32 drm_vblank_count(struct drm_device *dev, int crtc) { - return atomic_read(&dev->vblank[crtc].count); + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; + + return atomic_read(&vblank->count); } EXPORT_SYMBOL(drm_vblank_count); @@ -816,6 +826,7 @@ EXPORT_SYMBOL(drm_vblank_count); u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, struct timeval *vblanktime) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; u32 cur_vblank; /* Read timestamp from slot of _vblank_time ringbuffer @@ -824,10 +835,10 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, * a seqlock. */ do { - cur_vblank = atomic_read(&dev->vblank[crtc].count); + cur_vblank = atomic_read(&vblank->count); *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); smp_rmb(); - } while (cur_vblank != atomic_read(&dev->vblank[crtc].count)); + } while (cur_vblank != atomic_read(&vblank->count)); return cur_vblank; } @@ -882,13 +893,14 @@ EXPORT_SYMBOL(drm_send_vblank_event); */ static int drm_vblank_enable(struct drm_device *dev, int crtc) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; int ret = 0; assert_spin_locked(&dev->vbl_lock); spin_lock(&dev->vblank_time_lock); - if (!dev->vblank[crtc].enabled) { + if (!vblank->enabled) { /* * Enable vblank irqs under vblank_time_lock protection. * All vblank count & timestamp updates are held off @@ -899,9 +911,9 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc) ret = dev->driver->enable_vblank(dev, crtc); DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); if (ret) - atomic_dec(&dev->vblank[crtc].refcount); + atomic_dec(&vblank->refcount); else { - dev->vblank[crtc].enabled = true; + vblank->enabled = true; drm_update_vblank_count(dev, crtc); } } @@ -926,16 +938,17 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc) */ int drm_vblank_get(struct drm_device *dev, int crtc) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; unsigned long irqflags; int ret = 0; spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ - if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) { + if (atomic_add_return(1, &vblank->refcount) == 1) { ret = drm_vblank_enable(dev, crtc); } else { - if (!dev->vblank[crtc].enabled) { - atomic_dec(&dev->vblank[crtc].refcount); + if (!vblank->enabled) { + atomic_dec(&vblank->refcount); ret = -EINVAL; } } @@ -975,12 +988,14 @@ EXPORT_SYMBOL(drm_crtc_vblank_get); */ void drm_vblank_put(struct drm_device *dev, int crtc) { - BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0); + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; + + BUG_ON(atomic_read(&vblank->refcount) == 0); /* Last user schedules interrupt disable */ - if (atomic_dec_and_test(&dev->vblank[crtc].refcount) && + if (atomic_dec_and_test(&vblank->refcount) && (drm_vblank_offdelay > 0)) - mod_timer(&dev->vblank[crtc].disable_timer, + mod_timer(&vblank->disable_timer, jiffies + ((drm_vblank_offdelay * HZ)/1000)); } EXPORT_SYMBOL(drm_vblank_put); @@ -1016,6 +1031,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_put); */ void drm_vblank_off(struct drm_device *dev, int crtc) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; struct drm_pending_vblank_event *e, *t; struct timeval now; unsigned long irqflags; @@ -1023,7 +1039,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc) spin_lock_irqsave(&dev->vbl_lock, irqflags); vblank_disable_and_save(dev, crtc); - wake_up(&dev->vblank[crtc].queue); + wake_up(&vblank->queue); /* Send any queued vblank events, lest the natives grow disquiet */ seq = drm_vblank_count_and_time(dev, crtc, &now); @@ -1045,9 +1061,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc) * Prevent subsequent drm_vblank_get() from re-enabling * the vblank interrupt by bumping the refcount. */ - if (!dev->vblank[crtc].inmodeset) { - atomic_inc(&dev->vblank[crtc].refcount); - dev->vblank[crtc].inmodeset = 1; + if (!vblank->inmodeset) { + atomic_inc(&vblank->refcount); + vblank->inmodeset = 1; } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); @@ -1087,13 +1103,14 @@ EXPORT_SYMBOL(drm_crtc_vblank_off); */ void drm_vblank_on(struct drm_device *dev, int crtc) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; unsigned long irqflags; spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Drop our private "prevent drm_vblank_get" refcount */ - if (dev->vblank[crtc].inmodeset) { - atomic_dec(&dev->vblank[crtc].refcount); - dev->vblank[crtc].inmodeset = 0; + if (vblank->inmodeset) { + atomic_dec(&vblank->refcount); + vblank->inmodeset = 0; } /* @@ -1103,12 +1120,12 @@ void drm_vblank_on(struct drm_device *dev, int crtc) * -1 to make sure user will never see the same * vblank counter value before and after a modeset */ - dev->vblank[crtc].last = + vblank->last = (dev->driver->get_vblank_counter(dev, crtc) - 1) & dev->max_vblank_count; /* re-enable interrupts if there's are users left */ - if (atomic_read(&dev->vblank[crtc].refcount) != 0) + if (atomic_read(&vblank->refcount) != 0) WARN_ON(drm_vblank_enable(dev, crtc)); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } @@ -1156,6 +1173,8 @@ EXPORT_SYMBOL(drm_crtc_vblank_on); */ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; + /* vblank is not initialized (IRQ not installed ?), or has been freed */ if (!dev->num_crtcs) return; @@ -1166,10 +1185,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) * to avoid corrupting the count if multiple, mismatch calls occur), * so that interrupts remain enabled in the interim. */ - if (!dev->vblank[crtc].inmodeset) { - dev->vblank[crtc].inmodeset = 0x1; + if (!vblank->inmodeset) { + vblank->inmodeset = 0x1; if (drm_vblank_get(dev, crtc) == 0) - dev->vblank[crtc].inmodeset |= 0x2; + vblank->inmodeset |= 0x2; } } EXPORT_SYMBOL(drm_vblank_pre_modeset); @@ -1184,21 +1203,22 @@ EXPORT_SYMBOL(drm_vblank_pre_modeset); */ void drm_vblank_post_modeset(struct drm_device *dev, int crtc) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; unsigned long irqflags; /* vblank is not initialized (IRQ not installed ?), or has been freed */ if (!dev->num_crtcs) return; - if (dev->vblank[crtc].inmodeset) { + if (vblank->inmodeset) { spin_lock_irqsave(&dev->vbl_lock, irqflags); dev->vblank_disable_allowed = true; spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - if (dev->vblank[crtc].inmodeset & 0x2) + if (vblank->inmodeset & 0x2) drm_vblank_put(dev, crtc); - dev->vblank[crtc].inmodeset = 0; + vblank->inmodeset = 0; } } EXPORT_SYMBOL(drm_vblank_post_modeset); @@ -1333,6 +1353,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_vblank_crtc *vblank; union drm_wait_vblank *vblwait = data; int ret; unsigned int flags, seq, crtc, high_crtc; @@ -1362,6 +1383,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, if (crtc >= dev->num_crtcs) return -EINVAL; + vblank = &dev->vblank[crtc]; + ret = drm_vblank_get(dev, crtc); if (ret) { DRM_DEBUG("failed to acquire vblank counter, %d\n", ret); @@ -1394,11 +1417,11 @@ int drm_wait_vblank(struct drm_device *dev, void *data, DRM_DEBUG("waiting on vblank count %d, crtc %d\n", vblwait->request.sequence, crtc); - dev->vblank[crtc].last_wait = vblwait->request.sequence; - DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * HZ, + vblank->last_wait = vblwait->request.sequence; + DRM_WAIT_ON(ret, vblank->queue, 3 * HZ, (((drm_vblank_count(dev, crtc) - vblwait->request.sequence) <= (1 << 23)) || - !dev->vblank[crtc].enabled || + !vblank->enabled || !dev->irq_enabled)); if (ret != -EINTR) { @@ -1459,6 +1482,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) */ bool drm_handle_vblank(struct drm_device *dev, int crtc) { + struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; u32 vblcount; s64 diff_ns; struct timeval tvblank; @@ -1474,7 +1498,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) spin_lock_irqsave(&dev->vblank_time_lock, irqflags); /* Vblank irq handling disabled. Nothing to do. */ - if (!dev->vblank[crtc].enabled) { + if (!vblank->enabled) { spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); return false; } @@ -1484,7 +1508,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) */ /* Get current timestamp and count. */ - vblcount = atomic_read(&dev->vblank[crtc].count); + vblcount = atomic_read(&vblank->count); drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); /* Compute time difference to timestamp of last vblank */ @@ -1508,14 +1532,14 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) * the timestamp computed above. */ smp_mb__before_atomic(); - atomic_inc(&dev->vblank[crtc].count); + atomic_inc(&vblank->count); smp_mb__after_atomic(); } else { DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", crtc, (int) diff_ns); } - wake_up(&dev->vblank[crtc].queue); + wake_up(&vblank->queue); drm_handle_vblank_events(dev, crtc); spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); -- GitLab From 56cc279b29c7b204fe7d0943509ae209b8b128db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:51 +0300 Subject: [PATCH 0027/5088] drm: Fix deadlock between event_lock and vbl_lock/vblank_time_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently both drm_irq.c and several drivers call drm_vblank_put() while holding event_lock. Now that drm_vblank_put() can disable the vblank interrupt directly it may need to grab vbl_lock and vblank_time_lock. That causes deadlocks since we take the locks in the opposite order in two places in drm_irq.c. So let's make sure the locking order is always event_lock->vbl_lock->vblank_time_lock. In drm_vblank_off() pull up event_lock from underneath vbl_lock. Hold the event_lock across the whole operation to make sure we only send out the events that were on the queue when we disabled the interrupt, and not ones that got added just after (assuming drm_vblank_on() already managed to get called somewhere between). To sort the other deadlock pull the event_lock out from drm_handle_vblank_events() into drm_handle_vblank() to be taken outside vblank_time_lock. Add the appropriate assert_spin_locked() to drm_handle_vblank_events(). Reviewed-by: Matt Roper Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 47 +++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index b4460bf0e0e4..9353609c6770 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1037,14 +1037,25 @@ void drm_vblank_off(struct drm_device *dev, int crtc) unsigned long irqflags; unsigned int seq; - spin_lock_irqsave(&dev->vbl_lock, irqflags); + spin_lock_irqsave(&dev->event_lock, irqflags); + + spin_lock(&dev->vbl_lock); vblank_disable_and_save(dev, crtc); wake_up(&vblank->queue); + /* + * Prevent subsequent drm_vblank_get() from re-enabling + * the vblank interrupt by bumping the refcount. + */ + if (!vblank->inmodeset) { + atomic_inc(&vblank->refcount); + vblank->inmodeset = 1; + } + spin_unlock(&dev->vbl_lock); + /* Send any queued vblank events, lest the natives grow disquiet */ seq = drm_vblank_count_and_time(dev, crtc, &now); - spin_lock(&dev->event_lock); list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { if (e->pipe != crtc) continue; @@ -1055,18 +1066,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc) drm_vblank_put(dev, e->pipe); send_vblank_event(dev, e, seq, &now); } - spin_unlock(&dev->event_lock); - - /* - * Prevent subsequent drm_vblank_get() from re-enabling - * the vblank interrupt by bumping the refcount. - */ - if (!vblank->inmodeset) { - atomic_inc(&vblank->refcount); - vblank->inmodeset = 1; - } - - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + spin_unlock_irqrestore(&dev->event_lock, irqflags); } EXPORT_SYMBOL(drm_vblank_off); @@ -1446,12 +1446,11 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) { struct drm_pending_vblank_event *e, *t; struct timeval now; - unsigned long flags; unsigned int seq; - seq = drm_vblank_count_and_time(dev, crtc, &now); + assert_spin_locked(&dev->event_lock); - spin_lock_irqsave(&dev->event_lock, flags); + seq = drm_vblank_count_and_time(dev, crtc, &now); list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { if (e->pipe != crtc) @@ -1467,8 +1466,6 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) send_vblank_event(dev, e, seq, &now); } - spin_unlock_irqrestore(&dev->event_lock, flags); - trace_drm_vblank_event(crtc, seq); } @@ -1491,15 +1488,18 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) if (!dev->num_crtcs) return false; + spin_lock_irqsave(&dev->event_lock, irqflags); + /* Need timestamp lock to prevent concurrent execution with * vblank enable/disable, as this would cause inconsistent * or corrupted timestamps and vblank counts. */ - spin_lock_irqsave(&dev->vblank_time_lock, irqflags); + spin_lock(&dev->vblank_time_lock); /* Vblank irq handling disabled. Nothing to do. */ if (!vblank->enabled) { - spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); + spin_unlock(&dev->vblank_time_lock); + spin_unlock_irqrestore(&dev->event_lock, irqflags); return false; } @@ -1539,10 +1539,13 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) crtc, (int) diff_ns); } + spin_unlock(&dev->vblank_time_lock); + wake_up(&vblank->queue); drm_handle_vblank_events(dev, crtc); - spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); + spin_unlock_irqrestore(&dev->event_lock, irqflags); + return true; } EXPORT_SYMBOL(drm_handle_vblank); -- GitLab From ffe7c73a8d4f0caeebd5d220ddbf7126a4daca1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:52 +0300 Subject: [PATCH 0028/5088] drm: Fix race between drm_vblank_off() and drm_queue_vblank_event() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently it's possible that the following will happen: 1. drm_wait_vblank() calls drm_vblank_get() 2. drm_vblank_off() gets called 3. drm_wait_vblank() calls drm_queue_vblank_event() which adds the event to the queue event though vblank interrupts are currently disabled (and may not be re-enabled ever again). To fix the problem, add another vblank->enabled check into drm_queue_vblank_event(). drm_vblank_off() holds event_lock around the vblank disable, so no further locking needs to be added to drm_queue_vblank_event(). vblank disable from another source is not possible since drm_wait_vblank() already holds a vblank reference. Reviewed-by: Matt Roper Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 9353609c6770..b2428cb0c64d 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1270,6 +1270,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, union drm_wait_vblank *vblwait, struct drm_file *file_priv) { + struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; struct drm_pending_vblank_event *e; struct timeval now; unsigned long flags; @@ -1293,6 +1294,18 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, spin_lock_irqsave(&dev->event_lock, flags); + /* + * drm_vblank_off() might have been called after we called + * drm_vblank_get(). drm_vblank_off() holds event_lock + * around the vblank disable, so no need for further locking. + * The reference from drm_vblank_get() protects against + * vblank disable from another source. + */ + if (!vblank->enabled) { + ret = -EINVAL; + goto err_unlock; + } + if (file_priv->event_space < sizeof e->event) { ret = -EBUSY; goto err_unlock; -- GitLab From 4ed0ce3d0bccd74416ba6beb33a8a79d1617e97b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:53 +0300 Subject: [PATCH 0029/5088] drm: Disable vblank interrupt immediately when drm_vblank_offdelay<0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make drm_vblank_put() disable the vblank interrupt immediately when the refcount drops to zero and drm_vblank_offdelay<0. v2: Preserve the current drm_vblank_offdelay==0 'never disable' behaviur Reviewed-by: Matt Roper Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 1 + drivers/gpu/drm/drm_drv.c | 4 ++-- drivers/gpu/drm/drm_irq.c | 11 +++++++---- include/drm/drmP.h | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 1d3756d3176c..55923d00bd52 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -3386,6 +3386,7 @@ void (*disable_vblank) (struct drm_device *dev, int crtc); by scheduling a timer. The delay is accessible through the vblankoffdelay module parameter or the drm_vblank_offdelay global variable and expressed in milliseconds. Its default value is 5000 ms. + Zero means never disable, and a negative value means disable immediately. When a vertical blanking interrupt occurs drivers only need to call the diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 92bc6b1d9646..db03e16ca817 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -39,7 +39,7 @@ unsigned int drm_debug = 0; /* 1 to enable debug output */ EXPORT_SYMBOL(drm_debug); -unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ +int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ @@ -53,7 +53,7 @@ MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); MODULE_PARM_DESC(debug, "Enable debug output"); -MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]"); +MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index b2428cb0c64d..99145c4d536b 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -993,10 +993,13 @@ void drm_vblank_put(struct drm_device *dev, int crtc) BUG_ON(atomic_read(&vblank->refcount) == 0); /* Last user schedules interrupt disable */ - if (atomic_dec_and_test(&vblank->refcount) && - (drm_vblank_offdelay > 0)) - mod_timer(&vblank->disable_timer, - jiffies + ((drm_vblank_offdelay * HZ)/1000)); + if (atomic_dec_and_test(&vblank->refcount)) { + if (drm_vblank_offdelay < 0) + vblank_disable_fn((unsigned long)vblank); + else if (drm_vblank_offdelay > 0) + mod_timer(&vblank->disable_timer, + jiffies + ((drm_vblank_offdelay * HZ)/1000)); + } } EXPORT_SYMBOL(drm_vblank_put); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index a57646382086..24b32d453c60 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1345,7 +1345,7 @@ extern void drm_put_dev(struct drm_device *dev); extern void drm_unplug_dev(struct drm_device *dev); extern unsigned int drm_debug; -extern unsigned int drm_vblank_offdelay; +extern int drm_vblank_offdelay; extern unsigned int drm_timestamp_precision; extern unsigned int drm_timestamp_monotonic; -- GitLab From 00185e667009dda907887a4f84fbd02c6e651a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:54 +0300 Subject: [PATCH 0030/5088] drm: Add dev->vblank_disable_immediate flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a flag to drm_device which will cause the vblank code to bypass the disable timer and always disable the vblank interrupt immediately when the last reference is dropped. v2: Add some notes about the flag to the kernel doc Reviewed-by: Matt Roper Reviewed-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 6 ++++++ drivers/gpu/drm/drm_irq.c | 2 +- include/drm/drmP.h | 10 ++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 55923d00bd52..583edbffff1a 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -3387,6 +3387,12 @@ void (*disable_vblank) (struct drm_device *dev, int crtc); module parameter or the drm_vblank_offdelay global variable and expressed in milliseconds. Its default value is 5000 ms. Zero means never disable, and a negative value means disable immediately. + Drivers may override the behaviour by setting the + drm_device + vblank_disable_immediate flag, which when set + causes vblank interrupts to be disabled immediately regardless of the + drm_vblank_offdelay value. The flag should only be set if there's a + properly working hardware vblank counter present. When a vertical blanking interrupt occurs drivers only need to call the diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 99145c4d536b..8dbcc3f892d5 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -994,7 +994,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc) /* Last user schedules interrupt disable */ if (atomic_dec_and_test(&vblank->refcount)) { - if (drm_vblank_offdelay < 0) + if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0) vblank_disable_fn((unsigned long)vblank); else if (drm_vblank_offdelay > 0) mod_timer(&vblank->disable_timer, diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 24b32d453c60..17a5c10474bd 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1074,6 +1074,16 @@ struct drm_device { */ bool vblank_disable_allowed; + /* + * If true, vblank interrupt will be disabled immediately when the + * refcount drops to zero, as opposed to via the vblank disable + * timer. + * This can be set to true it the hardware has a working vblank + * counter and the driver uses drm_vblank_on() and drm_vblank_off() + * appropriately. + */ + bool vblank_disable_immediate; + /* array of size num_crtcs */ struct drm_vblank_crtc *vblank; -- GitLab From 21da27005f79d72499bb809616b15fd2c5c15319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:55 +0300 Subject: [PATCH 0031/5088] drm/i915: Opt out of vblank disable timer on >gen2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the vblank races are plugged, we can opt out of using the vblank disable timer and just let vblank interrupts get disabled immediately when the last reference is dropped. Gen2 is the exception since it has no hardware frame counter. Reviewed-by: Matt Roper Reviewed-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6ef9d6fabf80..845f0f6c1eeb 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -4680,6 +4680,14 @@ void intel_irq_init(struct drm_device *dev) dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ } + /* + * Opt out of the vblank disable timer on everything except gen2. + * Gen2 doesn't have a hardware frame counter and so depends on + * vblank interrupts to produce sane vblank seuquence numbers. + */ + if (!IS_GEN2(dev)) + dev->vblank_disable_immediate = true; + if (drm_core_check_feature(dev, DRIVER_MODESET)) { dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; -- GitLab From cd19e52aee922ffe5c50b6ed67acd58cc1b2738b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:56 +0300 Subject: [PATCH 0032/5088] drm: Kick start vblank interrupts at drm_vblank_on() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the user is interested in getting accurate vblank sequence numbers all the time they may disable the vblank disable timer entirely. In that case it seems appropriate to kick start the vblank interrupts already from drm_vblank_on(). v2: Adapt to the drm_vblank_offdelay ==0 vs <0 changes Reviewed-by: Matt Roper Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 8dbcc3f892d5..af33df1adc6d 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1126,9 +1126,12 @@ void drm_vblank_on(struct drm_device *dev, int crtc) vblank->last = (dev->driver->get_vblank_counter(dev, crtc) - 1) & dev->max_vblank_count; - - /* re-enable interrupts if there's are users left */ - if (atomic_read(&vblank->refcount) != 0) + /* + * re-enable interrupts if there are users left, or the + * user wishes vblank interrupts to be enabled all the time. + */ + if (atomic_read(&vblank->refcount) != 0 || + (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0)) WARN_ON(drm_vblank_enable(dev, crtc)); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } -- GitLab From d297e1037327884fe9545f434d720fd3e8f18c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:50:01 +0300 Subject: [PATCH 0033/5088] drm/i915: Update scanline_offset only for active crtcs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update_scanline_offset() in intel_sanitize_crtc() was supposed to be called only for active crtcs. But due to some underrun patches it now gets updated for all crtcs on gmch platforms. Move the update_scanline_offset() to the very beginning of intel_sanitize_crtc() where we update the vblank state. This seems like a better place anyway since the scanline offset ought to be up to date before we might need to consult it. So before any vblanky stuff happens. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8f6b932d8e79..de40a44e0ca0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12719,9 +12719,10 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); /* restore vblank interrupts to correct state */ - if (crtc->active) + if (crtc->active) { + update_scanline_offset(crtc); drm_vblank_on(dev, crtc->pipe); - else + } else drm_vblank_off(dev, crtc->pipe); /* We need to sanitize the plane -> pipe mapping first because this will @@ -12820,8 +12821,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) */ crtc->cpu_fifo_underrun_disabled = true; crtc->pch_fifo_underrun_disabled = true; - - update_scanline_offset(crtc); } } -- GitLab From 96a9fdd778037799f63c9ae272ec915dd3ad83dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:50:02 +0300 Subject: [PATCH 0034/5088] drm: Fix confusing debug message in drm_update_vblank_count() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that drm_update_vblank_count() can be called even when we're not about to enable the vblank interrupts we shouldn't print debug messages stating otherwise. Signed-off-by: Ville Syrjälä 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 af33df1adc6d..62dee812d28a 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -103,7 +103,7 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) crtc, vblank->last, cur_vblank, diff); } - DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", + DRM_DEBUG("updating vblank count on crtc %d, missed %d\n", crtc, diff); /* Reinitialize corresponding vblank timestamp if high-precision query -- GitLab From c50d7521617d823d769b280bc499e19e364434ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:49:59 +0300 Subject: [PATCH 0035/5088] drm: Store the vblank timestamp when adjusting the counter during disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During vblank disable the code tries to guess based on the timestamps whether we just missed one vblank or not. And if so it increments the counter. However it forgets to store the new timestamp to the approriate slot in our timestamp ring buffer. So anyone querying the timestamp for the resulting sequence number would get a stale timestamp. Fix it up by storing the new timestamp. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 62dee812d28a..aa9b06495067 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -198,6 +198,13 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) * hope for the best. */ if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) { + /* Store new timestamp in ringbuffer. */ + vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; + + /* Increment cooked vblank count. This also atomically commits + * the timestamp computed above. + */ + smp_mb__before_atomic(); atomic_inc(&vblank->count); smp_mb__after_atomic(); } -- GitLab From 79a093aea44f11fda0a5b4dbe4c1e29b2f586f4e Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Wed, 6 Aug 2014 03:22:44 +0200 Subject: [PATCH 0036/5088] drm: Remove drm_vblank_cleanup from drm_vblank_init error path. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_vblank_cleanup() would operate on non-existent dev->vblank data structure, as failure to allocate that data structure is what triggers the error path in the first place. Signed-off-by: Mario Kleiner Reviewed-by: Ville Syrjälä 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 aa9b06495067..6473089e5fd3 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -303,7 +303,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) return 0; err: - drm_vblank_cleanup(dev); + dev->num_crtcs = 0; return ret; } EXPORT_SYMBOL(drm_vblank_init); -- GitLab From cf4f7fc3e7336e2e946880890e60ed36178889ea Mon Sep 17 00:00:00 2001 From: Fabio Falzoi Date: Mon, 4 Aug 2014 17:08:07 +0200 Subject: [PATCH 0037/5088] ASoC: fsl-ssi: Support for SND_SOC_DAIFMT_CBM_CFS Add SND_SOC_DAIFMT_CBM_CFS support for Freescale architecture. Successfully tested on i.MX 6Quad Wandboard and UDOO boards connected to the pcm1792a codec. In CBM_CFS mode, when using a sample size of 16 bits, we cannot use CCSR_SSI_SCR_I2S_MODE_MASTER since we get a frame sync every 16 bits. Signed-off-by: Michael Trimarchi Signed-off-by: Fabio Falzoi Tested-by: Angelo Adamo Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 87eb5776a39b..2fc3e6683e4f 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -259,6 +259,11 @@ static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private) SND_SOC_DAIFMT_CBS_CFS; } +static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private) +{ + return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == + SND_SOC_DAIFMT_CBM_CFS; +} /** * fsl_ssi_isr: SSI interrupt handler * @@ -705,6 +710,23 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } } + if (!fsl_ssi_is_ac97(ssi_private)) { + u8 i2smode; + /* + * Switch to normal net mode in order to have a frame sync + * signal every 32 bits instead of 16 bits + */ + if (fsl_ssi_is_i2s_cbm_cfs(ssi_private) && sample_size == 16) + i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL | + CCSR_SSI_SCR_NET; + else + i2smode = ssi_private->i2s_mode; + + regmap_update_bits(regs, CCSR_SSI_SCR, + CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK, + channels == 1 ? 0 : i2smode); + } + /* * FIXME: The documentation says that SxCCR[WL] should not be * modified while the SSI is enabled. The only time this can @@ -724,11 +746,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK, wl); - if (!fsl_ssi_is_ac97(ssi_private)) - regmap_update_bits(regs, CCSR_SSI_SCR, - CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK, - channels == 1 ? 0 : ssi_private->i2s_mode); - return 0; } @@ -780,6 +797,7 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBS_CFS: ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER; regmap_update_bits(regs, CCSR_SSI_STCCR, @@ -853,6 +871,11 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, case SND_SOC_DAIFMT_CBM_CFM: scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; break; + case SND_SOC_DAIFMT_CBM_CFS: + strcr &= ~CCSR_SSI_STCR_TXDIR; + strcr |= CCSR_SSI_STCR_TFDIR; + scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; + break; default: return -EINVAL; } -- GitLab From f769cd247d2be5af377adf82882eddd1dce183c4 Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Tue, 5 Aug 2014 07:51:22 -0700 Subject: [PATCH 0038/5088] drm/i915: Set M2_N2 registers during mode set For Gen < 8, set M2_N2 registers on every mode set. This is required to make sure M2_N2 registers are set during boot, resume from sleep for cross- checking the state. The register is set only if DRRS is supported. v2: Patch rebased v3: Daniel's review comments - Removed HAS_DRRS(dev) and added bool has_drrs to pipe_config to track drrs support v4: Jesse's review comments - Made changes to set m2_n2 in intel_dp_set_m_n() Signed-off-by: Vandana Kannan Cc: Daniel Vetter Cc: Jesse Barnes Signed-off-by: Rodrigo Vivi Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 28 +++++++++++++++++++++------- drivers/gpu/drm/i915/intel_dp.c | 18 +++--------------- drivers/gpu/drm/i915/intel_drv.h | 3 ++- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 018fb7222f60..acee1416eb93 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -91,11 +91,11 @@ static int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj); -static void intel_dp_set_m_n(struct intel_crtc *crtc); static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc); static void intel_set_pipe_timings(struct intel_crtc *intel_crtc); static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, - struct intel_link_m_n *m_n); + struct intel_link_m_n *m_n, + struct intel_link_m_n *m2_n2); static void ironlake_set_pipeconf(struct drm_crtc *crtc); static void haswell_set_pipeconf(struct drm_crtc *crtc); static void intel_set_pipe_csc(struct drm_crtc *crtc); @@ -3980,7 +3980,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) if (intel_crtc->config.has_pch_encoder) { intel_cpu_transcoder_set_m_n(intel_crtc, - &intel_crtc->config.fdi_m_n); + &intel_crtc->config.fdi_m_n, NULL); } ironlake_set_pipeconf(crtc); @@ -4093,7 +4093,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) if (intel_crtc->config.has_pch_encoder) { intel_cpu_transcoder_set_m_n(intel_crtc, - &intel_crtc->config.fdi_m_n); + &intel_crtc->config.fdi_m_n, NULL); } haswell_set_pipeconf(crtc); @@ -5509,7 +5509,8 @@ static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, } static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, - struct intel_link_m_n *m_n) + struct intel_link_m_n *m_n, + struct intel_link_m_n *m2_n2) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -5521,6 +5522,18 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n); I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m); I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n); + /* M2_N2 registers to be set only for gen < 8 (M2_N2 available + * for gen < 8) and if DRRS is supported (to make sure the + * registers are not unnecessarily accessed). + */ + if (m2_n2 && INTEL_INFO(dev)->gen < 8 && + crtc->config.has_drrs) { + I915_WRITE(PIPE_DATA_M2(transcoder), + TU_SIZE(m2_n2->tu) | m2_n2->gmch_m); + I915_WRITE(PIPE_DATA_N2(transcoder), m2_n2->gmch_n); + I915_WRITE(PIPE_LINK_M2(transcoder), m2_n2->link_m); + I915_WRITE(PIPE_LINK_N2(transcoder), m2_n2->link_n); + } } else { I915_WRITE(PIPE_DATA_M_G4X(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); I915_WRITE(PIPE_DATA_N_G4X(pipe), m_n->gmch_n); @@ -5529,12 +5542,13 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, } } -static void intel_dp_set_m_n(struct intel_crtc *crtc) +void intel_dp_set_m_n(struct intel_crtc *crtc) { if (crtc->config.has_pch_encoder) intel_pch_transcoder_set_m_n(crtc, &crtc->config.dp_m_n); else - intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n); + intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n, + &crtc->config.dp_m2_n2); } static void vlv_update_pll(struct intel_crtc *crtc) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 805b6f63df0f..3ea5cef9bbe6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -828,20 +828,6 @@ intel_dp_set_clock(struct intel_encoder *encoder, } } -static void -intel_dp_set_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - enum transcoder transcoder = crtc->config.cpu_transcoder; - - I915_WRITE(PIPE_DATA_M2(transcoder), - TU_SIZE(m_n->tu) | m_n->gmch_m); - I915_WRITE(PIPE_DATA_N2(transcoder), m_n->gmch_n); - I915_WRITE(PIPE_LINK_M2(transcoder), m_n->link_m); - I915_WRITE(PIPE_LINK_N2(transcoder), m_n->link_n); -} - bool intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) @@ -867,6 +853,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, pipe_config->has_pch_encoder = true; pipe_config->has_dp_encoder = true; + pipe_config->has_drrs = false; pipe_config->has_audio = intel_dp->has_audio; if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { @@ -970,6 +957,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (intel_connector->panel.downclock_mode != NULL && intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) { + pipe_config->has_drrs = true; intel_link_compute_m_n(bpp, lane_count, intel_connector->panel.downclock_mode->clock, pipe_config->port_clock, @@ -4389,7 +4377,7 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate) val = I915_READ(reg); if (index > DRRS_HIGH_RR) { val |= PIPECONF_EDP_RR_MODE_SWITCH; - intel_dp_set_m2_n2(intel_crtc, &config->dp_m2_n2); + intel_dp_set_m_n(intel_crtc); } else { val &= ~PIPECONF_EDP_RR_MODE_SWITCH; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4b2664bd5b81..7a3cac095afe 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -324,6 +324,7 @@ struct intel_crtc_config { /* m2_n2 for eDP downclock */ struct intel_link_m_n dp_m2_n2; + bool has_drrs; /* * Frequence the dpll for the port should run at. Differs from the @@ -877,6 +878,7 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv); void hsw_disable_pc8(struct drm_i915_private *dev_priv); void intel_dp_get_m_n(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config); +void intel_dp_set_m_n(struct intel_crtc *crtc); int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n); void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config, @@ -892,7 +894,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, int intel_format_to_fourcc(int format); void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); - /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, -- GitLab From b95af8bee524974768681b2b92235e1e1e21bf1a Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Tue, 5 Aug 2014 07:51:23 -0700 Subject: [PATCH 0039/5088] drm/i915: State readout and cross-checking for dp_m2_n2 Adding relevant read out comparison code, in check_crtc_state, for the new member of crtc_config, dp_m2_n2, which was introduced to store link_m_n values for a DP downclock mode (if available). Suggested by Daniel. v2: Changed patch title. Daniel's review comments incorporated. Added relevant state readout code for M2_N2. dp_m2_n2 comparison to be done only when high RR is not in use (This is because alternate m_n register programming will be done only when low RR is being used). v3: Modified call to get_m2_n2 which had dp_m_n as param by mistake. Compare dp_m_n and dp_m2_n2 for gen 7 and below. compare the structures based on DRRS state for gen 8 and above. Save and restore M2 N2 registers for gen 7 and below v4: For Gen>=8, check M_N registers against dp_m_n and dp_m2_n2 as there is only one set of M_N registers v5: Removed the chunk which saves and restores M2_N2 registers. Modified get_m_n() to get M2_N2 registers as well. Modified the macro which compares hw.dp_m_n against sw.dp_m2_n2/sw.dp_m_n for gen > 8. v6: Added check to compare dp_m2_n2 only when DRRS is enabled v7: Modified drrs check to use has_drrs v8: Add has_drrs check before reading M2_N2 registers Signed-off-by: Vandana Kannan Cc: Daniel Vetter Cc: Jani Nikula Cc: Jesse Barnes Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 75 +++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index acee1416eb93..620a89961d36 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7149,7 +7149,8 @@ static void intel_pch_transcoder_get_m_n(struct intel_crtc *crtc, static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc, enum transcoder transcoder, - struct intel_link_m_n *m_n) + struct intel_link_m_n *m_n, + struct intel_link_m_n *m2_n2) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -7163,6 +7164,20 @@ static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc, m_n->gmch_n = I915_READ(PIPE_DATA_N1(transcoder)); m_n->tu = ((I915_READ(PIPE_DATA_M1(transcoder)) & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1; + /* Read M2_N2 registers only for gen < 8 (M2_N2 available for + * gen < 8) and if DRRS is supported (to make sure the + * registers are not unnecessarily read). + */ + if (m2_n2 && INTEL_INFO(dev)->gen < 8 && + crtc->config.has_drrs) { + m2_n2->link_m = I915_READ(PIPE_LINK_M2(transcoder)); + m2_n2->link_n = I915_READ(PIPE_LINK_N2(transcoder)); + m2_n2->gmch_m = I915_READ(PIPE_DATA_M2(transcoder)) + & ~TU_SIZE_MASK; + m2_n2->gmch_n = I915_READ(PIPE_DATA_N2(transcoder)); + m2_n2->tu = ((I915_READ(PIPE_DATA_M2(transcoder)) + & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1; + } } else { m_n->link_m = I915_READ(PIPE_LINK_M_G4X(pipe)); m_n->link_n = I915_READ(PIPE_LINK_N_G4X(pipe)); @@ -7181,14 +7196,15 @@ void intel_dp_get_m_n(struct intel_crtc *crtc, intel_pch_transcoder_get_m_n(crtc, &pipe_config->dp_m_n); else intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder, - &pipe_config->dp_m_n); + &pipe_config->dp_m_n, + &pipe_config->dp_m2_n2); } static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder, - &pipe_config->fdi_m_n); + &pipe_config->fdi_m_n, NULL); } static void ironlake_get_pfit_config(struct intel_crtc *crtc, @@ -10005,6 +10021,15 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, pipe_config->dp_m_n.gmch_m, pipe_config->dp_m_n.gmch_n, pipe_config->dp_m_n.link_m, pipe_config->dp_m_n.link_n, pipe_config->dp_m_n.tu); + + DRM_DEBUG_KMS("dp: %i, gmch_m2: %u, gmch_n2: %u, link_m2: %u, link_n2: %u, tu2: %u\n", + pipe_config->has_dp_encoder, + pipe_config->dp_m2_n2.gmch_m, + pipe_config->dp_m2_n2.gmch_n, + pipe_config->dp_m2_n2.link_m, + pipe_config->dp_m2_n2.link_n, + pipe_config->dp_m2_n2.tu); + DRM_DEBUG_KMS("requested mode:\n"); drm_mode_debug_printmodeline(&pipe_config->requested_mode); DRM_DEBUG_KMS("adjusted mode:\n"); @@ -10385,6 +10410,22 @@ intel_pipe_config_compare(struct drm_device *dev, return false; \ } +/* This is required for BDW+ where there is only one set of registers for + * switching between high and low RR. + * This macro can be used whenever a comparison has to be made between one + * hw state and multiple sw state variables. + */ +#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 " " \ + "(expected %i or %i, found %i)\n", \ + current_config->name, \ + current_config->alt_name, \ + pipe_config->name); \ + return false; \ + } + #define PIPE_CONF_CHECK_FLAGS(name, mask) \ if ((current_config->name ^ pipe_config->name) & (mask)) { \ DRM_ERROR("mismatch in " #name "(" #mask ") " \ @@ -10417,11 +10458,28 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(fdi_m_n.tu); PIPE_CONF_CHECK_I(has_dp_encoder); - 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 (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_I(adjusted_mode.crtc_hdisplay); PIPE_CONF_CHECK_I(adjusted_mode.crtc_htotal); @@ -10507,6 +10565,7 @@ intel_pipe_config_compare(struct drm_device *dev, #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I +#undef PIPE_CONF_CHECK_I_ALT #undef PIPE_CONF_CHECK_FLAGS #undef PIPE_CONF_CHECK_CLOCK_FUZZY #undef PIPE_CONF_QUIRK -- GitLab From 020178a1bcadf20b9d057988984f374c905d542e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 22 May 2014 19:36:03 +0300 Subject: [PATCH 0040/5088] drm: Add drm_crtc_vblank_waitqueue() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a small static inline helper to grab the vblank wait queue based on the drm_crtc. This is useful for drivers to do internal vblank waits using wait_event() & co. v2: Pimp commit message (Daniel) Add kernel doc (Daniel) Suggested-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 1 + include/drm/drmP.h | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 1d3756d3176c..972759489376 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -3400,6 +3400,7 @@ void (*disable_vblank) (struct drm_device *dev, int crtc); Vertical Blanking and Interrupt Handling Functions Reference !Edrivers/gpu/drm/drm_irq.c +!Iinclude/drm/drmP.h drm_crtc_vblank_waitqueue diff --git a/include/drm/drmP.h b/include/drm/drmP.h index d3d9be6b83ef..bb44c1ee557d 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1344,6 +1344,17 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, extern void drm_calc_timestamping_constants(struct drm_crtc *crtc, const struct drm_display_mode *mode); +/** + * drm_crtc_vblank_waitqueue - get vblank waitqueue for the CRTC + * @crtc: which CRTC's vblank waitqueue to retrieve + * + * This function returns a pointer to the vblank waitqueue for the CRTC. + * Drivers can use this to implement vblank waits using wait_event() & co. + */ +static inline wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc) +{ + return &crtc->dev->vblank[drm_crtc_index(crtc)].queue; +} /* Modesetting support */ extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc); -- GitLab From 210871b67cd201c198b61ca80e1c51cd4b58c051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 22 May 2014 19:00:50 +0300 Subject: [PATCH 0041/5088] drm/i915: Kill intel_crtc->vbl_wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Share the waitqueue that drm_irq uses when performing the vblank evade trick for atomic pipe updates. v2: Keep intel_pipe_handle_vblank() (Chris) Suggested-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 5 ----- drivers/gpu/drm/i915/intel_display.c | 2 -- drivers/gpu/drm/i915/intel_drv.h | 2 -- drivers/gpu/drm/i915/intel_sprite.c | 5 +++-- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 390ccc2a3096..0e44c433cfc3 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1989,14 +1989,9 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) static bool intel_pipe_handle_vblank(struct drm_device *dev, enum pipe pipe) { - struct intel_crtc *crtc; - if (!drm_handle_vblank(dev, pipe)) return false; - crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe)); - wake_up(&crtc->vbl_wait); - return true; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 620a89961d36..a9b351d1ff88 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11870,8 +11870,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_base = ~0; intel_crtc->cursor_cntl = ~0; - init_waitqueue_head(&intel_crtc->vbl_wait); - 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 7a3cac095afe..3198de3007be 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -425,8 +425,6 @@ struct intel_crtc { struct intel_pipe_wm active; } wm; - wait_queue_head_t vbl_wait; - int scanline_offset; struct intel_mmio_flip mmio_flip; }; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 168c6652cda1..d34a5696ffb6 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -53,6 +53,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl enum pipe pipe = crtc->pipe; long timeout = msecs_to_jiffies_timeout(1); int scanline, min, max, vblank_start; + wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); DEFINE_WAIT(wait); WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex)); @@ -81,7 +82,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl * other CPUs can see the task state update by the time we * read the scanline. */ - prepare_to_wait(&crtc->vbl_wait, &wait, TASK_UNINTERRUPTIBLE); + prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); scanline = intel_get_crtc_scanline(crtc); if (scanline < min || scanline > max) @@ -100,7 +101,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl local_irq_disable(); } - finish_wait(&crtc->vbl_wait, &wait); + finish_wait(wq, &wait); drm_vblank_put(dev, pipe); -- GitLab From 4811ff4f2388727a161ea49c2b0ddca95e44c7f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:07 +0300 Subject: [PATCH 0042/5088] drm/i915: Add chv_power_wells[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add chv_power_wells[] so we can start to build up the power well support for chv. Just the "always on" well there initialy. Signed-off-by: Ville Syrjälä Tested-by: Rafael Barbalho Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 615e341682c3..7dbd7892b968 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6574,6 +6574,15 @@ static struct i915_power_well vlv_power_wells[] = { }, }; +static struct i915_power_well chv_power_wells[] = { + { + .name = "always-on", + .always_on = 1, + .domains = VLV_ALWAYS_ON_POWER_DOMAINS, + .ops = &i9xx_always_on_power_well_ops, + }, +}; + static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv, enum punit_power_well power_well_id) { @@ -6610,6 +6619,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) } else if (IS_BROADWELL(dev_priv->dev)) { set_power_wells(power_domains, bdw_power_wells); hsw_pwr = power_domains; + } else if (IS_CHERRYVIEW(dev_priv->dev)) { + set_power_wells(power_domains, chv_power_wells); } else if (IS_VALLEYVIEW(dev_priv->dev)) { set_power_wells(power_domains, vlv_power_wells); } else { -- GitLab From 5d6f7ea752228788eddce0b9e268fa1f0eabdd7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:08 +0300 Subject: [PATCH 0043/5088] drm/i915: Add chv cmnlane power wells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV has two display PHYs so there are also two cmnlane power wells. Add the approriate code to power the wells up/down. Like on VLV we do the cmnreset assert/deassert and the DPLL refclock enabling at approriate times. This code actually works on my bsw. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 89 +++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e4d7607da2c4..c3338ca4ab17 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -514,6 +514,7 @@ enum punit_power_well { PUNIT_POWER_WELL_DPIO_TX_C_LANES_23 = 9, PUNIT_POWER_WELL_DPIO_RX0 = 10, PUNIT_POWER_WELL_DPIO_RX1 = 11, + PUNIT_POWER_WELL_DPIO_CMN_D = 12, PUNIT_POWER_WELL_NUM, }; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7dbd7892b968..8a78015dd51e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6254,6 +6254,64 @@ static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, vlv_set_power_well(dev_priv, power_well, false); } +static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + enum dpio_phy phy; + + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC && + power_well->data != PUNIT_POWER_WELL_DPIO_CMN_D); + + /* + * Enable the CRI clock source so we can get at the + * display and the reference clock for VGA + * hotplug / manual detection. + */ + if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) { + phy = DPIO_PHY0; + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + DPLL_REFA_CLK_ENABLE_VLV); + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); + } else { + phy = DPIO_PHY1; + I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) | + DPLL_REFA_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); + + /* Poll for phypwrgood signal */ + if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & PHY_POWERGOOD(phy), 1)) + DRM_ERROR("Display PHY %d is not power up\n", phy); + + I915_WRITE(DISPLAY_PHY_CONTROL, + PHY_COM_LANE_RESET_DEASSERT(phy, I915_READ(DISPLAY_PHY_CONTROL))); +} + +static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + enum dpio_phy phy; + + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC && + power_well->data != PUNIT_POWER_WELL_DPIO_CMN_D); + + if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) { + phy = DPIO_PHY0; + assert_pll_disabled(dev_priv, PIPE_A); + assert_pll_disabled(dev_priv, PIPE_B); + } else { + phy = DPIO_PHY1; + assert_pll_disabled(dev_priv, PIPE_C); + } + + I915_WRITE(DISPLAY_PHY_CONTROL, + PHY_COM_LANE_RESET_ASSERT(phy, I915_READ(DISPLAY_PHY_CONTROL))); + + vlv_set_power_well(dev_priv, power_well, false); +} + static void check_power_well_state(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { @@ -6445,6 +6503,18 @@ EXPORT_SYMBOL_GPL(i915_get_cdclk_freq); BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ BIT(POWER_DOMAIN_INIT)) +#define CHV_DPIO_CMN_BC_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_INIT)) + +#define CHV_DPIO_CMN_D_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ + BIT(POWER_DOMAIN_INIT)) + static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { .sync_hw = i9xx_always_on_power_well_noop, .enable = i9xx_always_on_power_well_noop, @@ -6452,6 +6522,13 @@ static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { .is_enabled = i9xx_always_on_power_well_enabled, }; +static const struct i915_power_well_ops chv_dpio_cmn_power_well_ops = { + .sync_hw = vlv_power_well_sync_hw, + .enable = chv_dpio_cmn_power_well_enable, + .disable = chv_dpio_cmn_power_well_disable, + .is_enabled = vlv_power_well_enabled, +}; + static struct i915_power_well i9xx_always_on_power_well[] = { { .name = "always-on", @@ -6581,6 +6658,18 @@ static struct i915_power_well chv_power_wells[] = { .domains = VLV_ALWAYS_ON_POWER_DOMAINS, .ops = &i9xx_always_on_power_well_ops, }, + { + .name = "dpio-common-bc", + .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS, + .data = PUNIT_POWER_WELL_DPIO_CMN_BC, + .ops = &chv_dpio_cmn_power_well_ops, + }, + { + .name = "dpio-common-d", + .domains = CHV_DPIO_CMN_D_POWER_DOMAINS, + .data = PUNIT_POWER_WELL_DPIO_CMN_D, + .ops = &chv_dpio_cmn_power_well_ops, + }, }; static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv, -- GitLab From a74d782c74644b2e50b3db61e115831cdc3e9010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:09 +0300 Subject: [PATCH 0044/5088] drm/i915: Kill intel_reset_dpio() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both VLV and CHV handle the cmnreset stuff in the power well code now, so intel_reset_dpio() is no longer needed. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 31 ---------------------------- 1 file changed, 31 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a9b351d1ff88..c0575ea1e196 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1513,34 +1513,6 @@ static void intel_init_dpio(struct drm_device *dev) } } -static void intel_reset_dpio(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (IS_CHERRYVIEW(dev)) { - enum dpio_phy phy; - u32 val; - - for (phy = DPIO_PHY0; phy < I915_NUM_PHYS_VLV; phy++) { - /* Poll for phypwrgood signal */ - if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & - PHY_POWERGOOD(phy), 1)) - DRM_ERROR("Display PHY %d is not power up\n", phy); - - /* - * Deassert common lane reset for PHY. - * - * This should only be done on init and resume from S3 - * with both PLLs disabled, or we risk losing DPIO and - * PLL synchronization. - */ - val = I915_READ(DISPLAY_PHY_CONTROL); - I915_WRITE(DISPLAY_PHY_CONTROL, - PHY_COM_LANE_RESET_DEASSERT(phy, val)); - } - } -} - static void vlv_enable_pll(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; @@ -12615,8 +12587,6 @@ void intel_modeset_init_hw(struct drm_device *dev) intel_init_clock_gating(dev); - intel_reset_dpio(dev); - intel_enable_gt_powersave(dev); } @@ -12687,7 +12657,6 @@ void intel_modeset_init(struct drm_device *dev) } intel_init_dpio(dev); - intel_reset_dpio(dev); intel_shared_dpll_init(dev); -- GitLab From f07057d13c62c5b925725c6e03a0c4d1c0244bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:10 +0300 Subject: [PATCH 0045/5088] drm/i915: Add disp2d power well for chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not sure if it's still there since chv has per-pipe power wells. At least with current Punit this doesn't work. Also the display irq handling would need to be adjusted for pipe C. So leave the code iffed out for now. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8a78015dd51e..dc8719f29d03 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6658,6 +6658,14 @@ static struct i915_power_well chv_power_wells[] = { .domains = VLV_ALWAYS_ON_POWER_DOMAINS, .ops = &i9xx_always_on_power_well_ops, }, +#if 0 + { + .name = "display", + .domains = VLV_DISPLAY_POWER_DOMAINS, + .data = PUNIT_POWER_WELL_DISP2D, + .ops = &vlv_display_power_well_ops, + }, +#endif { .name = "dpio-common-bc", .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS, -- GitLab From 26972b0a80091ccece1cbd9422772ae625a612f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:11 +0300 Subject: [PATCH 0046/5088] drm/i915: Add per-pipe power wells for chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV has a power well for each pipe. Add the code to deal with them. The Punit in current hardware doesn't seem ready for this yet, so leave it iffed out. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 12 +++ drivers/gpu/drm/i915/intel_pm.c | 126 ++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c3338ca4ab17..9d54aee6f8c8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -501,6 +501,18 @@ #define DSPFREQSTAT_MASK (0x3 << DSPFREQSTAT_SHIFT) #define DSPFREQGUAR_SHIFT 14 #define DSPFREQGUAR_MASK (0x3 << DSPFREQGUAR_SHIFT) +#define _DP_SSC(val, pipe) ((val) << (2 * (pipe))) +#define DP_SSC_MASK(pipe) _DP_SSC(0x3, (pipe)) +#define DP_SSC_PWR_ON(pipe) _DP_SSC(0x0, (pipe)) +#define DP_SSC_CLK_GATE(pipe) _DP_SSC(0x1, (pipe)) +#define DP_SSC_RESET(pipe) _DP_SSC(0x2, (pipe)) +#define DP_SSC_PWR_GATE(pipe) _DP_SSC(0x3, (pipe)) +#define _DP_SSS(val, pipe) ((val) << (2 * (pipe) + 16)) +#define DP_SSS_MASK(pipe) _DP_SSS(0x3, (pipe)) +#define DP_SSS_PWR_ON(pipe) _DP_SSS(0x0, (pipe)) +#define DP_SSS_CLK_GATE(pipe) _DP_SSS(0x1, (pipe)) +#define DP_SSS_RESET(pipe) _DP_SSS(0x2, (pipe)) +#define DP_SSS_PWR_GATE(pipe) _DP_SSS(0x3, (pipe)) /* See the PUNIT HAS v0.8 for the below bits */ enum punit_power_well { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index dc8719f29d03..95b3ca5964e9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6312,6 +6312,95 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, vlv_set_power_well(dev_priv, power_well, false); } +static bool chv_pipe_power_well_enabled(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + enum pipe pipe = power_well->data; + bool enabled; + u32 state, ctrl; + + mutex_lock(&dev_priv->rps.hw_lock); + + state = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSS_MASK(pipe); + /* + * We only ever set the power-on and power-gate states, anything + * else is unexpected. + */ + WARN_ON(state != DP_SSS_PWR_ON(pipe) && state != DP_SSS_PWR_GATE(pipe)); + enabled = state == DP_SSS_PWR_ON(pipe); + + /* + * A transient state at this point would mean some unexpected party + * is poking at the power controls too. + */ + ctrl = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSC_MASK(pipe); + WARN_ON(ctrl << 16 != state); + + mutex_unlock(&dev_priv->rps.hw_lock); + + return enabled; +} + +static void chv_set_pipe_power_well(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well, + bool enable) +{ + enum pipe pipe = power_well->data; + u32 state; + u32 ctrl; + + state = enable ? DP_SSS_PWR_ON(pipe) : DP_SSS_PWR_GATE(pipe); + + mutex_lock(&dev_priv->rps.hw_lock); + +#define COND \ + ((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSS_MASK(pipe)) == state) + + if (COND) + goto out; + + ctrl = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ); + ctrl &= ~DP_SSC_MASK(pipe); + ctrl |= enable ? DP_SSC_PWR_ON(pipe) : DP_SSC_PWR_GATE(pipe); + vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, ctrl); + + if (wait_for(COND, 100)) + DRM_ERROR("timout setting power well state %08x (%08x)\n", + state, + vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ)); + +#undef COND + +out: + mutex_unlock(&dev_priv->rps.hw_lock); +} + +static void chv_pipe_power_well_sync_hw(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + 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); + + chv_set_pipe_power_well(dev_priv, power_well, true); +} + +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); + + chv_set_pipe_power_well(dev_priv, power_well, false); +} + static void check_power_well_state(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { @@ -6503,6 +6592,18 @@ EXPORT_SYMBOL_GPL(i915_get_cdclk_freq); BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ BIT(POWER_DOMAIN_INIT)) +#define CHV_PIPE_A_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PIPE_A) | \ + BIT(POWER_DOMAIN_INIT)) + +#define CHV_PIPE_B_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PIPE_B) | \ + BIT(POWER_DOMAIN_INIT)) + +#define CHV_PIPE_C_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PIPE_C) | \ + BIT(POWER_DOMAIN_INIT)) + #define CHV_DPIO_CMN_BC_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ @@ -6522,6 +6623,13 @@ static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { .is_enabled = i9xx_always_on_power_well_enabled, }; +static const struct i915_power_well_ops chv_pipe_power_well_ops = { + .sync_hw = chv_pipe_power_well_sync_hw, + .enable = chv_pipe_power_well_enable, + .disable = chv_pipe_power_well_disable, + .is_enabled = chv_pipe_power_well_enabled, +}; + static const struct i915_power_well_ops chv_dpio_cmn_power_well_ops = { .sync_hw = vlv_power_well_sync_hw, .enable = chv_dpio_cmn_power_well_enable, @@ -6665,6 +6773,24 @@ static struct i915_power_well chv_power_wells[] = { .data = PUNIT_POWER_WELL_DISP2D, .ops = &vlv_display_power_well_ops, }, + { + .name = "pipe-a", + .domains = CHV_PIPE_A_POWER_DOMAINS, + .data = PIPE_A, + .ops = &chv_pipe_power_well_ops, + }, + { + .name = "pipe-b", + .domains = CHV_PIPE_B_POWER_DOMAINS, + .data = PIPE_B, + .ops = &chv_pipe_power_well_ops, + }, + { + .name = "pipe-c", + .domains = CHV_PIPE_C_POWER_DOMAINS, + .data = PIPE_C, + .ops = &chv_pipe_power_well_ops, + }, #endif { .name = "dpio-common-bc", -- GitLab From 8258356537871cf579868002552a0ed1762b0487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:12 +0300 Subject: [PATCH 0047/5088] drm/i915: Add chv port B and C TX wells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the TX wells for ports B and C just like on VLV. Again Punit doesn't seem ready (or the wells don't even exist anymore) so leave it iffed out. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 95b3ca5964e9..59157635d418 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6804,6 +6804,36 @@ static struct i915_power_well chv_power_wells[] = { .data = PUNIT_POWER_WELL_DPIO_CMN_D, .ops = &chv_dpio_cmn_power_well_ops, }, +#if 0 + { + .name = "dpio-tx-b-01", + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS, + .ops = &vlv_dpio_power_well_ops, + .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01, + }, + { + .name = "dpio-tx-b-23", + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS, + .ops = &vlv_dpio_power_well_ops, + .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23, + }, + { + .name = "dpio-tx-c-01", + .domains = VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS, + .ops = &vlv_dpio_power_well_ops, + .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01, + }, + { + .name = "dpio-tx-c-23", + .domains = VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS | + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS, + .ops = &vlv_dpio_power_well_ops, + .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23, + }, +#endif }; static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv, -- GitLab From 2ce147f36dc5a1f3b49abd8ce3164ad0f04ec863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:13 +0300 Subject: [PATCH 0048/5088] drm/i915: Add chv port D TX wells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the TX wells for port D. The Punit subsystem numbers are a total guess at this time. Also I'm not sure these even exist. Certainly the Punit in current hardware doesn't deal with these. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_pm.c | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9d54aee6f8c8..e01a1a0b9613 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -527,6 +527,10 @@ enum punit_power_well { PUNIT_POWER_WELL_DPIO_RX0 = 10, PUNIT_POWER_WELL_DPIO_RX1 = 11, PUNIT_POWER_WELL_DPIO_CMN_D = 12, + /* FIXME: guesswork below */ + PUNIT_POWER_WELL_DPIO_TX_D_LANES_01 = 13, + PUNIT_POWER_WELL_DPIO_TX_D_LANES_23 = 14, + PUNIT_POWER_WELL_DPIO_RX2 = 15, PUNIT_POWER_WELL_NUM, }; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 59157635d418..f4a1837c231c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6616,6 +6616,15 @@ EXPORT_SYMBOL_GPL(i915_get_cdclk_freq); BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ BIT(POWER_DOMAIN_INIT)) +#define CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ + BIT(POWER_DOMAIN_INIT)) + +#define CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS ( \ + BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ + BIT(POWER_DOMAIN_INIT)) + static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { .sync_hw = i9xx_always_on_power_well_noop, .enable = i9xx_always_on_power_well_noop, @@ -6833,6 +6842,20 @@ static struct i915_power_well chv_power_wells[] = { .ops = &vlv_dpio_power_well_ops, .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23, }, + { + .name = "dpio-tx-d-01", + .domains = CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS | + CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS, + .ops = &vlv_dpio_power_well_ops, + .data = PUNIT_POWER_WELL_DPIO_TX_D_LANES_01, + }, + { + .name = "dpio-tx-d-23", + .domains = CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS | + CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS, + .ops = &vlv_dpio_power_well_ops, + .data = PUNIT_POWER_WELL_DPIO_TX_D_LANES_23, + }, #endif }; -- GitLab From 026b96e293fbe48153ae868308e341f226d76c46 Mon Sep 17 00:00:00 2001 From: Rafael Barbalho Date: Mon, 28 Jul 2014 19:56:27 +0100 Subject: [PATCH 0049/5088] drm/i915: Fix read back of plane stride register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the specifications bit 6 is actually valid in the stride register. Cc: Jesse Barnes Cc: Ville Syrjälä Signed-off-by: Rafael Barbalho Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- 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 c0575ea1e196..71957e7184ef 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6211,7 +6211,7 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc, crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1; val = I915_READ(DSPSTRIDE(pipe)); - crtc->base.primary->fb->pitches[0] = val & 0xffffff80; + crtc->base.primary->fb->pitches[0] = val & 0xffffffc0; aligned_height = intel_align_height(dev, crtc->base.primary->fb->height, plane_config->tiled); @@ -7247,7 +7247,7 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc, crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1; val = I915_READ(DSPSTRIDE(pipe)); - crtc->base.primary->fb->pitches[0] = val & 0xffffff80; + crtc->base.primary->fb->pitches[0] = val & 0xffffffc0; aligned_height = intel_align_height(dev, crtc->base.primary->fb->height, plane_config->tiled); -- GitLab From a5043453aa2412ece984373294529d177324c901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:18 +0300 Subject: [PATCH 0050/5088] drm/i915: Split a few long debug prints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split some WM debug prints to multiple lines. This shouldn't hurt grappability since the important part is at the start and the rest is just repeated stuff for each pipe. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f4a1837c231c..a318cd5ad8ed 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1387,7 +1387,8 @@ static void valleyview_update_wm(struct drm_crtc *crtc) plane_sr = cursor_sr = 0; } - DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", + DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, " + "B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", planea_wm, cursora_wm, planeb_wm, cursorb_wm, plane_sr, cursor_sr); @@ -1443,7 +1444,8 @@ static void g4x_update_wm(struct drm_crtc *crtc) plane_sr = cursor_sr = 0; } - DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", + DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, " + "B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", planea_wm, cursora_wm, planeb_wm, cursorb_wm, plane_sr, cursor_sr); -- GitLab From aad3d14d25c33c8e510c41aaaf2668e8d32811ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:25 +0300 Subject: [PATCH 0051/5088] drm/i915: Add DP training pattern 3 for CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV supports DP training pattern 3. Add the required stuff. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_dp.c | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e01a1a0b9613..e355fc8d4d59 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3489,6 +3489,8 @@ enum punit_power_well { #define DP_LINK_TRAIN_OFF (3 << 28) #define DP_LINK_TRAIN_MASK (3 << 28) #define DP_LINK_TRAIN_SHIFT 28 +#define DP_LINK_TRAIN_PAT_3_CHV (1 << 14) +#define DP_LINK_TRAIN_MASK_CHV ((3 << 28)|(1<<14)) /* CPT Link training mode */ #define DP_LINK_TRAIN_PAT_1_CPT (0 << 8) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3ea5cef9bbe6..0aa219dff19c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2959,7 +2959,10 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, } } else { - *DP &= ~DP_LINK_TRAIN_MASK; + if (IS_CHERRYVIEW(dev)) + *DP &= ~DP_LINK_TRAIN_MASK_CHV; + else + *DP &= ~DP_LINK_TRAIN_MASK; switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { case DP_TRAINING_PATTERN_DISABLE: @@ -2972,8 +2975,12 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, *DP |= DP_LINK_TRAIN_PAT_2; break; case DP_TRAINING_PATTERN_3: - DRM_ERROR("DP training pattern 3 not supported\n"); - *DP |= DP_LINK_TRAIN_PAT_2; + if (IS_CHERRYVIEW(dev)) { + *DP |= DP_LINK_TRAIN_PAT_3_CHV; + } else { + DRM_ERROR("DP training pattern 3 not supported\n"); + *DP |= DP_LINK_TRAIN_PAT_2; + } break; } } @@ -3260,7 +3267,10 @@ intel_dp_link_down(struct intel_dp *intel_dp) DP &= ~DP_LINK_TRAIN_MASK_CPT; I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT); } else { - DP &= ~DP_LINK_TRAIN_MASK; + if (IS_CHERRYVIEW(dev)) + DP &= ~DP_LINK_TRAIN_MASK_CHV; + else + DP &= ~DP_LINK_TRAIN_MASK; I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE); } POSTING_READ(intel_dp->output_reg); -- GitLab From dcfc3552136fb6996e19b9f6980dc5a6721defd5 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 29 Jul 2014 18:06:16 +0100 Subject: [PATCH 0052/5088] drm/i915: Specify when the PLL hw state fields are valid Not all those fields are valid on a given platform. Make it explicit. Unions could also be used, but were cluttering some code paths with if/else ladders. v2: Don't use anonymous unions (Daniel) Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- 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 c70b2b67282e..c3beb08813c6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -197,10 +197,13 @@ enum intel_dpll_id { #define I915_NUM_PLLS 2 struct intel_dpll_hw_state { + /* i9xx, pch plls */ uint32_t dpll; uint32_t dpll_md; uint32_t fp0; uint32_t fp1; + + /* hsw, bdw */ uint32_t wrpll; }; -- GitLab From 74dd69280bc3f3e84d46b2a0f78901a0d9b4562c Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 29 Jul 2014 18:06:17 +0100 Subject: [PATCH 0053/5088] drm/i915: Add a space to the shared DPLL debug message Signed-off-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 71957e7184ef..0b8769b9422f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1778,7 +1778,7 @@ static void intel_enable_shared_dpll(struct intel_crtc *crtc) if (WARN_ON(pll->refcount == 0)) return; - DRM_DEBUG_KMS("enable %s (active %d, on? %d)for crtc %d\n", + DRM_DEBUG_KMS("enable %s (active %d, on? %d) for crtc %d\n", pll->name, pll->active, pll->on, crtc->base.base.id); -- GitLab From 7d2c81751c858442387fa5158d4cd80c2190d739 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 29 Jul 2014 18:06:18 +0100 Subject: [PATCH 0054/5088] drm/i915: Extract the HSW DDI selection code into its own function Future platform will slightly change that. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0b8769b9422f..c3bb5f7fd21b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7607,6 +7607,22 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, return 0; } +static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv, + enum port port, + struct intel_crtc_config *pipe_config) +{ + pipe_config->ddi_pll_sel = I915_READ(PORT_CLK_SEL(port)); + + switch (pipe_config->ddi_pll_sel) { + case PORT_CLK_SEL_WRPLL1: + pipe_config->shared_dpll = DPLL_ID_WRPLL1; + break; + case PORT_CLK_SEL_WRPLL2: + pipe_config->shared_dpll = DPLL_ID_WRPLL2; + break; + } +} + static void haswell_get_ddi_port_state(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { @@ -7620,16 +7636,7 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc, port = (tmp & TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT; - pipe_config->ddi_pll_sel = I915_READ(PORT_CLK_SEL(port)); - - switch (pipe_config->ddi_pll_sel) { - case PORT_CLK_SEL_WRPLL1: - pipe_config->shared_dpll = DPLL_ID_WRPLL1; - break; - case PORT_CLK_SEL_WRPLL2: - pipe_config->shared_dpll = DPLL_ID_WRPLL2; - break; - } + haswell_get_ddi_pll(dev_priv, port, pipe_config); if (pipe_config->shared_dpll >= 0) { pll = &dev_priv->shared_dplls[pipe_config->shared_dpll]; -- GitLab From 143b307c43dcfeae41a3b6c24a29fae4c70884f4 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 29 Jul 2014 18:06:19 +0100 Subject: [PATCH 0055/5088] drm/i915: Extract the HSW/BDW shared dpll init code So we can easily provide an alternate implementation in the future. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 5db0b5552e39..ee7a74c6e93a 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1248,10 +1248,8 @@ static const char * const hsw_ddi_pll_names[] = { "WRPLL 2", }; -void intel_ddi_pll_init(struct drm_device *dev) +static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t val = I915_READ(LCPLL_CTL); int i; dev_priv->num_shared_dpll = 2; @@ -1264,6 +1262,14 @@ void intel_ddi_pll_init(struct drm_device *dev) dev_priv->shared_dplls[i].get_hw_state = hsw_ddi_pll_get_hw_state; } +} + +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); + + hsw_shared_dplls_init(dev_priv); /* The LCPLL register should be turned on by the BIOS. For now let's * just check its state and print errors in case something is wrong. -- GitLab From ea155f32cea99f17371bec00ee9c8e3713a15d4f Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 29 Jul 2014 18:06:20 +0100 Subject: [PATCH 0056/5088] drm/i915: Restrict hsw_dp_set_ddi_pll_sel() to HSW/BDW Future platform will use config->ddi_pll_sel in a different way. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0aa219dff19c..16fcfc67f014 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -964,7 +964,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, &pipe_config->dp_m2_n2); } - if (HAS_DDI(dev)) + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) hsw_dp_set_ddi_pll_sel(pipe_config, intel_dp->link_bw); else intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); -- GitLab From bf9584bd0e99bd284e115ea8eba9b02a5a2d7b4d Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 29 Jul 2014 18:06:21 +0100 Subject: [PATCH 0057/5088] drm/i915: Fix stale comment for intel_ddi_pll_select() Since the run-time PM on DPMS series, this function has an outdated comment. Refresh it a bit. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index ee7a74c6e93a..3b6375d3e422 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -709,10 +709,11 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */, } /* - * Tries to find a PLL for the CRTC. If it finds, it increases the refcount and - * stores it in intel_crtc->ddi_pll_sel, so other mode sets won't be able to - * steal the selected PLL. You need to call intel_ddi_pll_enable to actually - * enable the PLL. + * Tries to find a *shared* PLL for the CRTC and store it in + * intel_crtc->ddi_pll_sel. + * + * For private DPLLs, compute_config() should do the selection for us. This + * function should be folded into compute_config() eventually. */ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) { -- GitLab From 0220ab6e00785da008bb3736737b877d45858608 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 29 Jul 2014 18:06:22 +0100 Subject: [PATCH 0058/5088] drm/i915: Split the BDW/HSW specific shared pll selection We'll need a different algorithm to select the shared DPLL. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 39 +++++++++++++++++++------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3b6375d3e422..09599851f1a8 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -708,23 +708,10 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */, *r2_out = best.r2; } -/* - * Tries to find a *shared* PLL for the CRTC and store it in - * intel_crtc->ddi_pll_sel. - * - * For private DPLLs, compute_config() should do the selection for us. This - * function should be folded into compute_config() eventually. - */ -bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) +static bool +hsw_ddi_pll_select(struct intel_crtc *intel_crtc, int output, int clock) { - struct drm_crtc *crtc = &intel_crtc->base; - struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); - int type = intel_encoder->type; - int clock = intel_crtc->config.port_clock; - - intel_put_shared_dpll(intel_crtc); - - if (type == INTEL_OUTPUT_HDMI) { + if (output == INTEL_OUTPUT_HDMI) { struct intel_shared_dpll *pll; uint32_t val; unsigned p, n2, r2; @@ -750,6 +737,26 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) return true; } + +/* + * Tries to find a *shared* PLL for the CRTC and store it in + * intel_crtc->ddi_pll_sel. + * + * For private DPLLs, compute_config() should do the selection for us. This + * function should be folded into compute_config() eventually. + */ +bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) +{ + struct drm_crtc *crtc = &intel_crtc->base; + struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); + int type = intel_encoder->type; + int clock = intel_crtc->config.port_clock; + + intel_put_shared_dpll(intel_crtc); + + return hsw_ddi_pll_select(intel_crtc, type, clock); +} + void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; -- GitLab From d664c0cece2dd410d8134aa820112e471e3592dd Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 29 Jul 2014 18:06:23 +0100 Subject: [PATCH 0059/5088] drm/i915: Make intel_ddi_calculate_wrpll() HSW/BDW specific Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 09599851f1a8..eb8e494ce569 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -644,8 +644,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder, } static void -intel_ddi_calculate_wrpll(int clock /* in Hz */, - unsigned *r2_out, unsigned *n2_out, unsigned *p_out) +hsw_ddi_calculate_wrpll(int clock /* in Hz */, + unsigned *r2_out, unsigned *n2_out, unsigned *p_out) { uint64_t freq2k; unsigned p, n2, r2; @@ -709,14 +709,16 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */, } static bool -hsw_ddi_pll_select(struct intel_crtc *intel_crtc, int output, int clock) +hsw_ddi_pll_select(struct intel_crtc *intel_crtc, + struct intel_encoder *intel_encoder, + int clock) { - if (output == INTEL_OUTPUT_HDMI) { + if (intel_encoder->type == INTEL_OUTPUT_HDMI) { struct intel_shared_dpll *pll; uint32_t val; unsigned p, n2, r2; - intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); + hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL | WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | @@ -749,12 +751,11 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) { struct drm_crtc *crtc = &intel_crtc->base; struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); - int type = intel_encoder->type; int clock = intel_crtc->config.port_clock; intel_put_shared_dpll(intel_crtc); - return hsw_ddi_pll_select(intel_crtc, type, clock); + return hsw_ddi_pll_select(intel_crtc, intel_encoder, clock); } void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) -- GitLab From ad13d6048f5002f1c5ab21c71a5ee136a2d8e889 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 29 Jul 2014 18:06:24 +0100 Subject: [PATCH 0060/5088] drm/i915: Split the CDCLK retrieval per-platform This is only going to get worse, so split it now to avoid adding more cases to the if/else ladder. Suggested-by: Daniel Vetter Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 55 ++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index eb8e494ce569..b5870fd920ff 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1192,31 +1192,52 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) } } -int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) +static int bdw_get_cdclk_freq(struct drm_i915_private *dev_priv) +{ + uint32_t lcpll = I915_READ(LCPLL_CTL); + uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK; + + if (lcpll & LCPLL_CD_SOURCE_FCLK) + return 800000; + else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) + return 450000; + else if (freq == LCPLL_CLK_FREQ_450) + return 450000; + else if (freq == LCPLL_CLK_FREQ_54O_BDW) + return 540000; + else if (freq == LCPLL_CLK_FREQ_337_5_BDW) + return 337500; + else + return 675000; +} + +static int hsw_get_cdclk_freq(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; uint32_t lcpll = I915_READ(LCPLL_CTL); uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK; - if (lcpll & LCPLL_CD_SOURCE_FCLK) { + if (lcpll & LCPLL_CD_SOURCE_FCLK) return 800000; - } else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) { + else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) return 450000; - } else if (freq == LCPLL_CLK_FREQ_450) { + else if (freq == LCPLL_CLK_FREQ_450) return 450000; - } else if (IS_HASWELL(dev)) { - if (IS_ULT(dev)) - return 337500; - else - return 540000; - } else { - if (freq == LCPLL_CLK_FREQ_54O_BDW) - return 540000; - else if (freq == LCPLL_CLK_FREQ_337_5_BDW) - return 337500; - else - return 675000; - } + else if (IS_ULT(dev)) + return 337500; + else + return 540000; +} + +int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + + if (IS_BROADWELL(dev)) + return bdw_get_cdclk_freq(dev_priv); + + /* Haswell */ + return hsw_get_cdclk_freq(dev_priv); } static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv, -- GitLab From 3d51278af91f8e96077dad3a4c1cc0b19fa8ca25 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 29 Jul 2014 20:57:08 +0200 Subject: [PATCH 0061/5088] drm/i915: Make ddi_clock_gate() HSW/BDW specific Turns out we were again way too naive and optimistic, of course things will change. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b5870fd920ff..3634575534b4 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -587,8 +587,8 @@ static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, return (refclk * n * 100) / (p * r); } -void intel_ddi_clock_get(struct intel_encoder *encoder, - struct intel_crtc_config *pipe_config) +static void hsw_ddi_clock_get(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; int link_clock = 0; @@ -643,6 +643,12 @@ void intel_ddi_clock_get(struct intel_encoder *encoder, pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock; } +void intel_ddi_clock_get(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + hsw_ddi_clock_get(encoder, pipe_config); +} + static void hsw_ddi_calculate_wrpll(int clock /* in Hz */, unsigned *r2_out, unsigned *n2_out, unsigned *p_out) @@ -1480,7 +1486,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder, dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp; } - intel_ddi_clock_get(encoder, pipe_config); + hsw_ddi_clock_get(encoder, pipe_config); } static void intel_ddi_destroy(struct drm_encoder *encoder) -- GitLab From 06ffc7789e76a095e85814dbcf7b660344f6b679 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 17 Jul 2014 17:43:46 -0300 Subject: [PATCH 0062/5088] d rm/i915: freeze display before the interrupts and GT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we started using intel_runtime_pm_disable_interrupts() at normal (non-runtime) suspend/resume, we had to remove a WARN from ironlake_disable_display_irq to avoid a case where we were doing the correct thing and the WARN was not really needed. The problem is that the WARN was useful in other cases, and its removal can hide some bugs that we would catch automatically. To be able to add back the WARN, we have to call intel_crtc_control() before interrupts are disabled, which is what this patch currently does. Also notice that Ville's patch from the Watermarks series "drm/i915: Leave interrupts enabled while disabling crtcs during suspend" also did a change that's equivalent to the one we're doing on this patch, with the exception that its original patch, when applied to the current tree, procduces a WARN. Related commits: commit daa390e5ee45cc051d6bf37b296901f2f92b002d Author: Jesse Barnes drm/i915: don't warn if IRQs are disabled when shutting down display IRQs commit e11aa362308f5de467ce355a2a2471321b15a35c Author: Jesse Barnes drm/i915: use runtime irq suspend/resume in freeze/thaw Note that the function part of this patch has already been done 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) with the fixup commit 09b64267c1f72f2670fcde9f11e5453ce365ca23 Author: Dave Airlie Date: Wed Jul 23 14:25:24 2014 +1000 drm/i915: don't suspend gt until after we disable irqs and display (v2) so all that's left from Paulo's patch is reinstating the WARNING. Cc: Ville Syrjälä Cc: Jesse Barnes Signed-off-by: Paulo Zanoni Reviewed-by: Jesse Barnes [danvet: Explain conflict resolution with Dave's DP MST patches with a note in the commit message.] Signed-off-by: Daniel Vetter --- 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 0e44c433cfc3..379cfb5dc731 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -151,7 +151,7 @@ ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask) { assert_spin_locked(&dev_priv->irq_lock); - if (!intel_irqs_enabled(dev_priv)) + if (WARN_ON(!intel_irqs_enabled(dev_priv))) return; if ((dev_priv->irq_mask & mask) != mask) { -- GitLab From 383c5a6a4682f6816fb5a07aebd89c5813c3d1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:03:57 +0300 Subject: [PATCH 0063/5088] drm/i915: Add cdclk change support for chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like the Punit is supposed to support the 400MHz cdclk directly on chv, so we don't need the vlv tricks. FIXME: Punit doesn't seem ready for this yet on current hw Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 +++ drivers/gpu/drm/i915/intel_display.c | 50 ++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e355fc8d4d59..697c04976cd3 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -497,6 +497,10 @@ #define BUNIT_REG_BISOC 0x11 #define PUNIT_REG_DSPFREQ 0x36 +#define DSPFREQSTAT_SHIFT_CHV 24 +#define DSPFREQSTAT_MASK_CHV (0x1f << DSPFREQSTAT_SHIFT_CHV) +#define DSPFREQGUAR_SHIFT_CHV 8 +#define DSPFREQGUAR_MASK_CHV (0x1f << DSPFREQGUAR_SHIFT_CHV) #define DSPFREQSTAT_SHIFT 30 #define DSPFREQSTAT_MASK (0x3 << DSPFREQSTAT_SHIFT) #define DSPFREQGUAR_SHIFT 14 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c3bb5f7fd21b..fdf5ec88866a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4501,6 +4501,47 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) vlv_update_cdclk(dev); } +static void cherryview_set_cdclk(struct drm_device *dev, int cdclk) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val, cmd; + + WARN_ON(dev_priv->display.get_display_clock_speed(dev) != dev_priv->vlv_cdclk_freq); + + switch (cdclk) { + case 400000: + cmd = 3; + break; + case 333333: + case 320000: + cmd = 2; + break; + case 266667: + cmd = 1; + break; + case 200000: + cmd = 0; + break; + default: + WARN_ON(1); + return; + } + + mutex_lock(&dev_priv->rps.hw_lock); + val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ); + val &= ~DSPFREQGUAR_MASK_CHV; + val |= (cmd << DSPFREQGUAR_SHIFT_CHV); + vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val); + if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & + DSPFREQSTAT_MASK_CHV) == (cmd << DSPFREQSTAT_SHIFT_CHV), + 50)) { + DRM_ERROR("timed out waiting for CDclk change\n"); + } + mutex_unlock(&dev_priv->rps.hw_lock); + + vlv_update_cdclk(dev); +} + static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, int max_pixclk) { @@ -4569,8 +4610,13 @@ static void valleyview_modeset_global_resources(struct drm_device *dev) int max_pixclk = intel_mode_max_pixclk(dev_priv); int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); - if (req_cdclk != dev_priv->vlv_cdclk_freq) - valleyview_set_cdclk(dev, req_cdclk); + if (req_cdclk != dev_priv->vlv_cdclk_freq) { + if (IS_CHERRYVIEW(dev)) + cherryview_set_cdclk(dev, req_cdclk); + else + valleyview_set_cdclk(dev, req_cdclk); + } + modeset_update_crtc_power_domains(dev); } -- GitLab From d49a340d6eb6de45c1a886b71469d110f2dbb57b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:03:58 +0300 Subject: [PATCH 0064/5088] drm/i915: Disable cdclk changes for chv until Punit is ready MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Punit seems a bit WIP still. Disable cdclk changes until we have hardware where it works. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes 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 fdf5ec88866a..a7d0c88a620d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4548,6 +4548,10 @@ static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, int vco = valleyview_get_vco(dev_priv); int freq_320 = (vco << 1) % 320000 != 0 ? 333333 : 320000; + /* FIXME: Punit isn't quite ready yet */ + if (IS_CHERRYVIEW(dev_priv->dev)) + return 400000; + /* * Really only a few cases to deal with, as only 4 CDclks are supported: * 200MHz @@ -5283,6 +5287,10 @@ static int valleyview_get_display_clock_speed(struct drm_device *dev) u32 val; int divider; + /* FIXME: Punit isn't quite ready yet */ + if (IS_CHERRYVIEW(dev)) + return 400000; + mutex_lock(&dev_priv->dpio_lock); val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); mutex_unlock(&dev_priv->dpio_lock); -- GitLab From d17ec4ced6c0907f80f51677a44236da94ecd92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:03:59 +0300 Subject: [PATCH 0065/5088] drm/i915: Leave DPLL ref clocks on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We enable the DPLL refclock already when bringing up the cmnlane power well, so also leave it on when otherwise disabling the DPLL. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes 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 a7d0c88a620d..6ca53b372a4c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1684,7 +1684,7 @@ 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; + val = DPLL_SSC_REF_CLOCK_CHV | DPLL_REFA_CLK_ENABLE_VLV; if (pipe != PIPE_A) val |= DPLL_INTEGRATED_CRI_CLK_VLV; I915_WRITE(DPLL(pipe), val); -- GitLab From 1ae0d1377fda91367b27596001c82e877ec2057e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:00 +0300 Subject: [PATCH 0066/5088] drm/i915: Split chv_update_pll() apart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split chv_update_pll() into two parts ala: commit bdd4b6a655749970cc632aafc5fd596c07b60b1c Author: Daniel Vetter Date: Thu Apr 24 23:55:11 2014 +0200 drm/i915: Extract vlv_prepare_pll Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 30 ++++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6ca53b372a4c..60ba6962026b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -100,6 +100,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc); static void haswell_set_pipeconf(struct drm_crtc *crtc); static void intel_set_pipe_csc(struct drm_crtc *crtc); static void vlv_prepare_pll(struct intel_crtc *crtc); +static void chv_prepare_pll(struct intel_crtc *crtc); static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) { @@ -4642,8 +4643,12 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) is_dsi = intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI); - if (!is_dsi && !IS_CHERRYVIEW(dev)) - vlv_prepare_pll(intel_crtc); + if (!is_dsi) { + if (IS_CHERRYVIEW(dev)) + chv_prepare_pll(intel_crtc); + else + vlv_prepare_pll(intel_crtc); + } /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; @@ -5691,6 +5696,18 @@ static void vlv_prepare_pll(struct intel_crtc *crtc) } static void chv_update_pll(struct intel_crtc *crtc) +{ + crtc->config.dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV | + DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | + DPLL_VCO_ENABLE; + if (crtc->pipe != PIPE_A) + crtc->config.dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; + + crtc->config.dpll_hw_state.dpll_md = + (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; +} + +static void chv_prepare_pll(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -5701,15 +5718,6 @@ static void chv_update_pll(struct intel_crtc *crtc) u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac; int refclk; - crtc->config.dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | - DPLL_VCO_ENABLE; - if (pipe != PIPE_A) - crtc->config.dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; - - crtc->config.dpll_hw_state.dpll_md = - (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; - bestn = crtc->config.dpll.n; bestm2_frac = crtc->config.dpll.m2 & 0x3fffff; bestm1 = crtc->config.dpll.m1; -- GitLab From 625695f8c3383765fd8974616aa57ffdbc644f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:02 +0300 Subject: [PATCH 0067/5088] drm/i915: Call intel_{dp, hdmi}_prepare for chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV was forgotten the intel_{dp,hdmi}_prepare() were introduced (or the chv patches were still in flight?). Call these when enabling the ports. Things tend to work much better when we actually write something to the port registers :) Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 2 ++ drivers/gpu/drm/i915/intel_hdmi.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 16fcfc67f014..33a45a819525 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2281,6 +2281,8 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder) enum pipe pipe = intel_crtc->pipe; u32 val; + intel_dp_prepare(encoder); + mutex_lock(&dev_priv->dpio_lock); /* program left/right clock distribution */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f9151f6641d9..df25b740b348 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1260,6 +1260,8 @@ static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder) enum pipe pipe = intel_crtc->pipe; u32 val; + intel_hdmi_prepare(encoder); + mutex_lock(&dev_priv->dpio_lock); /* program left/right clock distribution */ -- GitLab From 1fb44505f6c547742fcbcba4d3999fb324b5f587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 28 Jun 2014 02:04:03 +0300 Subject: [PATCH 0068/5088] drm/i915: Clarify CHV swing margin/deemph bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV display PHY registes have two swing margin/deemph settings. Make it clear which ones we're using. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++-- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- drivers/gpu/drm/i915/intel_hdmi.c | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 697c04976cd3..35553aa0a82f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -855,8 +855,8 @@ enum punit_power_well { #define _VLV_TX_DW2_CH0 0x8288 #define _VLV_TX_DW2_CH1 0x8488 -#define DPIO_SWING_MARGIN_SHIFT 16 -#define DPIO_SWING_MARGIN_MASK (0xff << DPIO_SWING_MARGIN_SHIFT) +#define DPIO_SWING_MARGIN000_SHIFT 16 +#define DPIO_SWING_MARGIN000_MASK (0xff << DPIO_SWING_MARGIN000_SHIFT) #define DPIO_UNIQ_TRANS_SCALE_SHIFT 8 #define VLV_TX_DW2(ch) _PORT(ch, _VLV_TX_DW2_CH0, _VLV_TX_DW2_CH1) @@ -864,12 +864,16 @@ enum punit_power_well { #define _VLV_TX_DW3_CH1 0x848c /* The following bit for CHV phy */ #define DPIO_TX_UNIQ_TRANS_SCALE_EN (1<<27) +#define DPIO_SWING_MARGIN101_SHIFT 16 +#define DPIO_SWING_MARGIN101_MASK (0xff << DPIO_SWING_MARGIN101_SHIFT) #define VLV_TX_DW3(ch) _PORT(ch, _VLV_TX_DW3_CH0, _VLV_TX_DW3_CH1) #define _VLV_TX_DW4_CH0 0x8290 #define _VLV_TX_DW4_CH1 0x8490 #define DPIO_SWING_DEEMPH9P5_SHIFT 24 #define DPIO_SWING_DEEMPH9P5_MASK (0xff << DPIO_SWING_DEEMPH9P5_SHIFT) +#define DPIO_SWING_DEEMPH6P0_SHIFT 16 +#define DPIO_SWING_DEEMPH6P0_MASK (0xff << DPIO_SWING_DEEMPH6P0_SHIFT) #define VLV_TX_DW4(ch) _PORT(ch, _VLV_TX_DW4_CH0, _VLV_TX_DW4_CH1) #define _VLV_TX3_DW4_CH0 0x690 diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 33a45a819525..95b972736733 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2649,8 +2649,8 @@ static uint32_t intel_chv_signal_levels(struct intel_dp *intel_dp) /* Program swing margin */ for (i = 0; i < 4; i++) { val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i)); - val &= ~DPIO_SWING_MARGIN_MASK; - val |= margin_reg_value << DPIO_SWING_MARGIN_SHIFT; + val &= ~DPIO_SWING_MARGIN000_MASK; + val |= margin_reg_value << DPIO_SWING_MARGIN000_SHIFT; vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val); } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index df25b740b348..5f47d359a991 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1431,8 +1431,8 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder) for (i = 0; i < 4; i++) { val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i)); - val &= ~DPIO_SWING_MARGIN_MASK; - val |= 102 << DPIO_SWING_MARGIN_SHIFT; + val &= ~DPIO_SWING_MARGIN000_MASK; + val |= 102 << DPIO_SWING_MARGIN000_SHIFT; vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val); } -- GitLab From 7f0c860533ff2de4b3bb84f71d5ce238fffe4d63 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Wed, 30 Jul 2014 20:34:57 +0530 Subject: [PATCH 0069/5088] drm/i915: Add support for Video Burst Mode for MIPI DSI v2: Updated the error log as suggested by Imre Signed-off-by: Shobhit Kumar Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.h | 3 +- drivers/gpu/drm/i915/intel_dsi.c | 22 ++++++++----- drivers/gpu/drm/i915/intel_dsi.h | 2 ++ drivers/gpu/drm/i915/intel_dsi_panel_vbt.c | 38 ++++++++++++++++++++-- drivers/gpu/drm/i915/intel_dsi_pll.c | 9 ++--- 5 files changed, 57 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index b98667796337..905999bee2ac 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -802,7 +802,8 @@ struct mipi_config { u16 rsvd4; - u8 rsvd5[5]; + u8 rsvd5; + u32 target_burst_mode_freq; u32 dsi_ddr_clk; u32 bridge_ref_clk; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 670c29a7b5dd..aea8f3383c26 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -423,9 +423,11 @@ static u16 txclkesc(u32 divider, unsigned int us) } /* return pixels in terms of txbyteclkhs */ -static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count) +static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count, + u16 burst_mode_ratio) { - return DIV_ROUND_UP(DIV_ROUND_UP(pixels * bpp, 8), lane_count); + return DIV_ROUND_UP(DIV_ROUND_UP(pixels * bpp * burst_mode_ratio, + 8 * 100), lane_count); } static void set_dsi_timings(struct drm_encoder *encoder, @@ -451,10 +453,12 @@ static void set_dsi_timings(struct drm_encoder *encoder, vbp = mode->vtotal - mode->vsync_end; /* horizontal values are in terms of high speed byte clock */ - hactive = txbyteclkhs(hactive, bpp, lane_count); - hfp = txbyteclkhs(hfp, bpp, lane_count); - hsync = txbyteclkhs(hsync, bpp, lane_count); - hbp = txbyteclkhs(hbp, bpp, lane_count); + hactive = txbyteclkhs(hactive, bpp, lane_count, + intel_dsi->burst_mode_ratio); + hfp = txbyteclkhs(hfp, bpp, lane_count, intel_dsi->burst_mode_ratio); + hsync = txbyteclkhs(hsync, bpp, lane_count, + intel_dsi->burst_mode_ratio); + hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio); I915_WRITE(MIPI_HACTIVE_AREA_COUNT(pipe), hactive); I915_WRITE(MIPI_HFP_COUNT(pipe), hfp); @@ -541,12 +545,14 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) intel_dsi->video_mode_format == VIDEO_MODE_BURST) { I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe), txbyteclkhs(adjusted_mode->htotal, bpp, - intel_dsi->lane_count) + 1); + intel_dsi->lane_count, + intel_dsi->burst_mode_ratio) + 1); } else { I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe), txbyteclkhs(adjusted_mode->vtotal * adjusted_mode->htotal, - bpp, intel_dsi->lane_count) + 1); + bpp, intel_dsi->lane_count, + intel_dsi->burst_mode_ratio) + 1); } I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout); I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val); diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index fd51867fd0d3..657eb5c1b9d8 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -116,6 +116,8 @@ struct intel_dsi { u16 clk_hs_to_lp_count; u16 init_count; + u32 pclk; + u16 burst_mode_ratio; /* all delays in ms */ u16 backlight_off_delay; diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index 47c7584a4aa0..f6bdd44069ce 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -271,6 +271,8 @@ static bool generic_init(struct intel_dsi_device *dsi) u32 ths_prepare_ns, tclk_trail_ns; u32 tclk_prepare_clkzero, ths_prepare_hszero; u32 lp_to_hs_switch, hs_to_lp_switch; + u32 pclk, computed_ddr; + u16 burst_mode_ratio; DRM_DEBUG_KMS("\n"); @@ -284,8 +286,6 @@ static bool generic_init(struct intel_dsi_device *dsi) else if (intel_dsi->pixel_format == VID_MODE_FORMAT_RGB565) bits_per_pixel = 16; - bitrate = (mode->clock * bits_per_pixel) / intel_dsi->lane_count; - intel_dsi->operation_mode = mipi_config->is_cmd_mode; intel_dsi->video_mode_format = mipi_config->video_transfer_mode; intel_dsi->escape_clk_div = mipi_config->byte_clk_sel; @@ -297,6 +297,40 @@ static bool generic_init(struct intel_dsi_device *dsi) intel_dsi->video_frmt_cfg_bits = mipi_config->bta_enabled ? DISABLE_VIDEO_BTA : 0; + pclk = mode->clock; + + /* Burst Mode Ratio + * Target ddr frequency from VBT / non burst ddr freq + * multiply by 100 to preserve remainder + */ + if (intel_dsi->video_mode_format == VIDEO_MODE_BURST) { + if (mipi_config->target_burst_mode_freq) { + computed_ddr = + (pclk * bits_per_pixel) / intel_dsi->lane_count; + + if (mipi_config->target_burst_mode_freq < + computed_ddr) { + DRM_ERROR("Burst mode freq is less than computed\n"); + return false; + } + + burst_mode_ratio = DIV_ROUND_UP( + mipi_config->target_burst_mode_freq * 100, + computed_ddr); + + pclk = DIV_ROUND_UP(pclk * burst_mode_ratio, 100); + } else { + DRM_ERROR("Burst mode target is not set\n"); + return false; + } + } else + burst_mode_ratio = 100; + + intel_dsi->burst_mode_ratio = burst_mode_ratio; + intel_dsi->pclk = pclk; + + bitrate = (pclk * bits_per_pixel) / intel_dsi->lane_count; + switch (intel_dsi->escape_clk_div) { case 0: tlpx_ns = 50; diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index d8bb1ea2f0da..06fad93a68c8 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -134,8 +134,7 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, #else /* Get DSI clock from pixel clock */ -static u32 dsi_clk_from_pclk(const struct drm_display_mode *mode, - int pixel_format, int lane_count) +static u32 dsi_clk_from_pclk(u32 pclk, int pixel_format, int lane_count) { u32 dsi_clk_khz; u32 bpp; @@ -156,7 +155,7 @@ static u32 dsi_clk_from_pclk(const struct drm_display_mode *mode, /* DSI data rate = pixel clock * bits per pixel / lane count pixel clock is converted from KHz to Hz */ - dsi_clk_khz = DIV_ROUND_CLOSEST(mode->clock * bpp, lane_count); + dsi_clk_khz = DIV_ROUND_CLOSEST(pclk * bpp, lane_count); return dsi_clk_khz; } @@ -228,14 +227,12 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) static void vlv_configure_dsi_pll(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); - const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int ret; struct dsi_mnp dsi_mnp; u32 dsi_clk; - dsi_clk = dsi_clk_from_pclk(mode, intel_dsi->pixel_format, + 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); -- GitLab From 7f3de8336fc8c44bede43c57e40448171b12ef68 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 30 Jul 2014 22:34:27 +0200 Subject: [PATCH 0070/5088] drm/i915: Align intel_dsi*.c files a bit I'm not really that insisting on checkpath compliance, but ragged function paramter alignment does get me. Please adjust your editor to just do this for you. Cc: Shobhit Kumar Cc: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi.c | 24 ++++++++++++------------ drivers/gpu/drm/i915/intel_dsi_cmd.c | 2 +- drivers/gpu/drm/i915/intel_dsi_pll.c | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index aea8f3383c26..5bd9e09ad3c5 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -184,7 +184,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; tmp = I915_READ(DSPCLK_GATE_D); tmp |= DPOUNIT_CLOCK_GATE_DISABLE; @@ -259,8 +259,8 @@ static void intel_dsi_disable(struct intel_encoder *encoder) temp = I915_READ(MIPI_CTRL(pipe)); temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; I915_WRITE(MIPI_CTRL(pipe), temp | - intel_dsi->escape_clk_div << - ESCAPE_CLOCK_DIVIDER_SHIFT); + intel_dsi->escape_clk_div << + ESCAPE_CLOCK_DIVIDER_SHIFT); I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP); @@ -297,7 +297,7 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) usleep_range(2000, 2500); if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & AFE_LATCHOUT) - == 0x00000), 30)) + == 0x00000), 30)) DRM_ERROR("DSI LP not going Low\n"); val = I915_READ(MIPI_PORT_CTRL(pipe)); @@ -427,7 +427,7 @@ static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count, u16 burst_mode_ratio) { return DIV_ROUND_UP(DIV_ROUND_UP(pixels * bpp * burst_mode_ratio, - 8 * 100), lane_count); + 8 * 100), lane_count); } static void set_dsi_timings(struct drm_encoder *encoder, @@ -454,10 +454,10 @@ static void set_dsi_timings(struct drm_encoder *encoder, /* horizontal values are in terms of high speed byte clock */ hactive = txbyteclkhs(hactive, bpp, lane_count, - intel_dsi->burst_mode_ratio); + intel_dsi->burst_mode_ratio); hfp = txbyteclkhs(hfp, bpp, lane_count, intel_dsi->burst_mode_ratio); hsync = txbyteclkhs(hsync, bpp, lane_count, - intel_dsi->burst_mode_ratio); + intel_dsi->burst_mode_ratio); hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio); I915_WRITE(MIPI_HACTIVE_AREA_COUNT(pipe), hactive); @@ -582,7 +582,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) * XXX: write MIPI_STOP_STATE_STALL? */ I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), - intel_dsi->hs_to_lp_count); + intel_dsi->hs_to_lp_count); /* XXX: low power clock equivalence in terms of byte clock. the number * of byte clocks occupied in one low power clock. based on txbyteclkhs @@ -607,10 +607,10 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) * 64 like 1366 x 768. Enable RANDOM resolution support for such * panels by default */ I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe), - intel_dsi->video_frmt_cfg_bits | - intel_dsi->video_mode_format | - IP_TG_CONFIG | - RANDOM_DPI_DISPLAY_RESOLUTION); + intel_dsi->video_frmt_cfg_bits | + intel_dsi->video_mode_format | + IP_TG_CONFIG | + RANDOM_DPI_DISPLAY_RESOLUTION); } static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.c b/drivers/gpu/drm/i915/intel_dsi_cmd.c index 7f1430ac8543..f4767fd2ebeb 100644 --- a/drivers/gpu/drm/i915/intel_dsi_cmd.c +++ b/drivers/gpu/drm/i915/intel_dsi_cmd.c @@ -430,7 +430,7 @@ void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi) u32 mask; mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY | - LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY; + LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY; if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == mask, 100)) DRM_ERROR("DPI FIFOs are not empty\n"); diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 06fad93a68c8..fa7a6ca34cd6 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -190,7 +190,7 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) for (m = 62; m <= 92; m++) { for (p = 2; p <= 6; p++) { /* Find the optimal m and p divisors - with minimal error +/- the required clock */ + with minimal error +/- the required clock */ calc_dsi_clk = (m * ref_clk) / p; if (calc_dsi_clk == target_dsi_clk) { calc_m = m; @@ -233,7 +233,7 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder) u32 dsi_clk; dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format, - intel_dsi->lane_count); + intel_dsi->lane_count); ret = dsi_calc_mnp(dsi_clk, &dsi_mnp); if (ret) { @@ -315,8 +315,8 @@ static void assert_bpp_mismatch(int pixel_format, int pipe_bpp) } WARN(bpp != pipe_bpp, - "bpp match assertion failure (expected %d, current %d)\n", - bpp, pipe_bpp); + "bpp match assertion failure (expected %d, current %d)\n", + bpp, pipe_bpp); } u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp) -- GitLab From da46f936bb0396f6a0fb87c2786f541e9f19a73c Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 1 Aug 2014 02:04:45 -0700 Subject: [PATCH 0071/5088] drm/i915: Introduce FBC False Color for debug purposes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this bit enabled, HW changes the color when compressing frames for debug purposes. ALthough the simple way to enable a single bit is over intel_reg_write, this value is overwriten on next update_fbc so depending on the workload it is not possible to set this bit with intel-gpu-tools. So this patch introduces a persistent way to enable false color over debugfs. v2: Use DEFINE_SIMPLE_ATTRIBUTE as Daniel suggested v3: (Ville) only do false color for IVB+ since according to spec bit is MBZ before IVB. v4: We don't have FBC on valleyview nor on cherryview (Ben) v5: s/!HAS_PCH_SPLIT/!HAS_FBC (Ville) Cc: Ville Syrjälä Reviewed-by: Ben Widawsky Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 42 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 3 +++ 4 files changed, 48 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9e737b771c40..aea1a819c775 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1433,6 +1433,47 @@ static int i915_fbc_status(struct seq_file *m, void *unused) return 0; } +static int i915_fbc_fc_get(void *data, u64 *val) +{ + struct drm_device *dev = data; + struct drm_i915_private *dev_priv = dev->dev_private; + + 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; +} + +static int i915_fbc_fc_set(void *data, u64 val) +{ + struct drm_device *dev = data; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; + + if (INTEL_INFO(dev)->gen < 7 || !HAS_FBC(dev)) + return -ENODEV; + + drm_modeset_lock_all(dev); + + reg = I915_READ(ILK_DPFC_CONTROL); + dev_priv->fbc.false_color = val; + + I915_WRITE(ILK_DPFC_CONTROL, val ? + (reg | FBC_CTL_FALSE_COLOR) : + (reg & ~FBC_CTL_FALSE_COLOR)); + + drm_modeset_unlock_all(dev); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(i915_fbc_fc_fops, + i915_fbc_fc_get, i915_fbc_fc_set, + "%llu\n"); + static int i915_ips_status(struct seq_file *m, void *unused) { struct drm_info_node *node = m->private; @@ -3957,6 +3998,7 @@ static const struct i915_debugfs_files { {"i915_pri_wm_latency", &i915_pri_wm_latency_fops}, {"i915_spr_wm_latency", &i915_spr_wm_latency_fops}, {"i915_cur_wm_latency", &i915_cur_wm_latency_fops}, + {"i915_fbc_false_color", &i915_fbc_fc_fops}, }; void intel_display_crc_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c3beb08813c6..ce30bb3ed566 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -637,6 +637,8 @@ struct i915_fbc { struct drm_mm_node compressed_fb; struct drm_mm_node *compressed_llb; + bool false_color; + struct intel_fbc_work { struct delayed_work work; struct drm_crtc *crtc; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 35553aa0a82f..ca37febbc2ae 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1540,6 +1540,7 @@ enum punit_power_well { /* Framebuffer compression for Ironlake */ #define ILK_DPFC_CB_BASE 0x43200 #define ILK_DPFC_CONTROL 0x43208 +#define FBC_CTL_FALSE_COLOR (1<<10) /* The bit 28-8 is reserved */ #define DPFC_RESERVED (0x1FFFFF00) #define ILK_DPFC_RECOMP_CTL 0x4320c diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a318cd5ad8ed..ab80df2909e0 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -309,6 +309,9 @@ static void gen7_enable_fbc(struct drm_crtc *crtc) dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN; + if (dev_priv->fbc.false_color) + dpfc_ctl |= FBC_CTL_FALSE_COLOR; + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); if (IS_IVYBRIDGE(dev)) { -- GitLab From ce4dd49e97813740bd2b03ecdc51521be10f3bf1 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 1 Aug 2014 11:07:54 +0100 Subject: [PATCH 0072/5088] drm/i915: Gather the HDMI level shifter logic into one place The knowledge about the HDMI/DVI DDI translation table was scattered around. - info->hdmi_level_shift was initialized with 6, the index of the 800 mV, 0dB translation - A check on the VBT value was done to ensure it wasn't overflowing the translation table (< 0xC) - The actual programming was done in intel_ddi.c As we need to change that knowledge for Broadwell, let's gather everything into one place. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 ++++++ drivers/gpu/drm/i915/intel_bios.c | 13 +++++-------- drivers/gpu/drm/i915/intel_ddi.c | 14 +++++++++++++- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ce30bb3ed566..0d7e55f2a8a2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1232,6 +1232,12 @@ enum modeset_restore { }; struct ddi_vbt_port_info { + /* + * This is an index in the HDMI/DVI DDI buffer translation table. + * The special value HDMI_LEVEL_SHIFT_UNKNOWN means the VBT didn't + * populate this field. + */ +#define HDMI_LEVEL_SHIFT_UNKNOWN 0xff uint8_t hdmi_level_shift; uint8_t supports_dvi:1; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index a66955037e4e..031c5657255d 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -976,12 +976,10 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, if (bdb->version >= 158) { /* The VBT HDMI level shift values match the table we have. */ hdmi_level_shift = child->raw[7] & 0xF; - if (hdmi_level_shift < 0xC) { - DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n", - port_name(port), - hdmi_level_shift); - info->hdmi_level_shift = hdmi_level_shift; - } + DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n", + port_name(port), + hdmi_level_shift); + info->hdmi_level_shift = hdmi_level_shift; } } @@ -1114,8 +1112,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; - /* Recommended BSpec default: 800mV 0dB. */ - info->hdmi_level_shift = 6; + info->hdmi_level_shift = HDMI_LEVEL_SHIFT_UNKNOWN; info->supports_dvi = (port != PORT_A && port != PORT_E); info->supports_hdmi = info->supports_dvi; diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3634575534b4..3af8340b21ec 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -145,7 +145,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; u32 reg; - int i; + int i, n_hdmi_entries, hdmi_800mV_0dB; int hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift; const u32 *ddi_translations_fdi; const u32 *ddi_translations_dp; @@ -156,15 +156,21 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) ddi_translations_fdi = bdw_ddi_translations_fdi; ddi_translations_dp = bdw_ddi_translations_dp; ddi_translations_edp = bdw_ddi_translations_edp; + n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); + hdmi_800mV_0dB = 6; } else if (IS_HASWELL(dev)) { ddi_translations_fdi = hsw_ddi_translations_fdi; ddi_translations_dp = hsw_ddi_translations_dp; ddi_translations_edp = hsw_ddi_translations_dp; + n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); + hdmi_800mV_0dB = 6; } else { WARN(1, "ddi translation table missing\n"); ddi_translations_edp = bdw_ddi_translations_dp; ddi_translations_fdi = bdw_ddi_translations_fdi; ddi_translations_dp = bdw_ddi_translations_dp; + n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); + hdmi_800mV_0dB = 6; } switch (port) { @@ -193,6 +199,12 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) I915_WRITE(reg, ddi_translations[i]); reg += 4; } + + /* Choose a good default if VBT is badly populated */ + if (hdmi_level == HDMI_LEVEL_SHIFT_UNKNOWN || + hdmi_level >= n_hdmi_entries) + hdmi_level = hdmi_800mV_0dB; + /* Entry 9 is for HDMI: */ for (i = 0; i < 2; i++) { I915_WRITE(reg, hsw_ddi_translations_hdmi[hdmi_level * 2 + i]); -- GitLab From a26aa8baee6c274fc23efccf46e891e63c8d0a30 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 1 Aug 2014 11:07:55 +0100 Subject: [PATCH 0073/5088] drm/i915/bdw: Provide the BDW specific HDMI buffer translation table Among the changes, the tables has only 10 entries instead of 12 on HSW and the index the the 800mV/0dB entry has changed. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3af8340b21ec..75ac0b29aa3e 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -111,6 +111,20 @@ static const u32 bdw_ddi_translations_fdi[] = { 0x00FFFFFF, 0x00140006 /* HDMI parameters 800mV 0dB*/ }; +static const u32 bdw_ddi_translations_hdmi[] = { + /* Idx NT mV diff T mV diff 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 */ +}; + enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; @@ -150,18 +164,21 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) const u32 *ddi_translations_fdi; const u32 *ddi_translations_dp; const u32 *ddi_translations_edp; + const u32 *ddi_translations_hdmi; const u32 *ddi_translations; if (IS_BROADWELL(dev)) { ddi_translations_fdi = bdw_ddi_translations_fdi; ddi_translations_dp = bdw_ddi_translations_dp; ddi_translations_edp = bdw_ddi_translations_edp; - n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); - hdmi_800mV_0dB = 6; + ddi_translations_hdmi = bdw_ddi_translations_hdmi; + n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); + hdmi_800mV_0dB = 7; } else if (IS_HASWELL(dev)) { ddi_translations_fdi = hsw_ddi_translations_fdi; ddi_translations_dp = hsw_ddi_translations_dp; ddi_translations_edp = hsw_ddi_translations_dp; + ddi_translations_hdmi = hsw_ddi_translations_hdmi; n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); hdmi_800mV_0dB = 6; } else { @@ -169,8 +186,9 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) ddi_translations_edp = bdw_ddi_translations_dp; ddi_translations_fdi = bdw_ddi_translations_fdi; ddi_translations_dp = bdw_ddi_translations_dp; - n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); - hdmi_800mV_0dB = 6; + ddi_translations_hdmi = bdw_ddi_translations_hdmi; + n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); + hdmi_800mV_0dB = 7; } switch (port) { @@ -207,7 +225,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) /* Entry 9 is for HDMI: */ for (i = 0; i < 2; i++) { - I915_WRITE(reg, hsw_ddi_translations_hdmi[hdmi_level * 2 + i]); + I915_WRITE(reg, ddi_translations_hdmi[hdmi_level * 2 + i]); reg += 4; } } -- GitLab From 156ae28c9f327d2c026e91cfacb5e224bb760d66 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 1 Aug 2014 11:07:56 +0100 Subject: [PATCH 0074/5088] drm/i915/bdw: Remove the HDMI/DVI entry from the DP/eDP/FDI tables We always write entries 0 to 8 from the DDI translation tables and then entry 9 for HDMI/DVI with the help of the VBT. We then don't need the failsafe HDMI entry in the DP/eDP/FDI tables. 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, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 75ac0b29aa3e..694e1c6118aa 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -82,7 +82,6 @@ static const u32 bdw_ddi_translations_edp[] = { 0x00BEEFFF, 0x000A000C, 0x00FFFFFF, 0x0005000F, 0x00DB6FFF, 0x000A000C, - 0x00FFFFFF, 0x00140006 /* HDMI parameters 800mV 0dB*/ }; static const u32 bdw_ddi_translations_dp[] = { @@ -95,7 +94,6 @@ static const u32 bdw_ddi_translations_dp[] = { 0x80CB2FFF, 0x001B0002, 0x00F7DFFF, 0x00180004, 0x80D75FFF, 0x001B0002, - 0x00FFFFFF, 0x00140006 /* HDMI parameters 800mV 0dB*/ }; static const u32 bdw_ddi_translations_fdi[] = { @@ -108,7 +106,6 @@ static const u32 bdw_ddi_translations_fdi[] = { 0x00C30FFF, 0x000C0000, 0x00FFFFFF, 0x00070006, 0x00D75FFF, 0x000C0000, - 0x00FFFFFF, 0x00140006 /* HDMI parameters 800mV 0dB*/ }; static const u32 bdw_ddi_translations_hdmi[] = { -- GitLab From ac921bdde92a354e8c59ea185dff26dc2611ee81 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 1 Aug 2014 11:07:57 +0100 Subject: [PATCH 0075/5088] drm/i915: Remove now useless comments about the translation values We used to carry a default HDMI value in entry 9, but this entry got removed for both HSW and BDW. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 694e1c6118aa..ca1f9a8a7d03 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -33,7 +33,7 @@ * automatically adapt to HDMI connections as well */ static const u32 hsw_ddi_translations_dp[] = { - 0x00FFFFFF, 0x0006000E, /* DP parameters */ + 0x00FFFFFF, 0x0006000E, 0x00D75FFF, 0x0005000A, 0x00C30FFF, 0x00040006, 0x80AAAFFF, 0x000B0000, @@ -45,7 +45,7 @@ static const u32 hsw_ddi_translations_dp[] = { }; static const u32 hsw_ddi_translations_fdi[] = { - 0x00FFFFFF, 0x0007000E, /* FDI parameters */ + 0x00FFFFFF, 0x0007000E, 0x00D75FFF, 0x000F000A, 0x00C30FFF, 0x00060006, 0x00AAAFFF, 0x001E0000, @@ -73,7 +73,7 @@ static const u32 hsw_ddi_translations_hdmi[] = { }; static const u32 bdw_ddi_translations_edp[] = { - 0x00FFFFFF, 0x00000012, /* eDP parameters */ + 0x00FFFFFF, 0x00000012, 0x00EBAFFF, 0x00020011, 0x00C71FFF, 0x0006000F, 0x00AAAFFF, 0x000E000A, @@ -85,7 +85,7 @@ static const u32 bdw_ddi_translations_edp[] = { }; static const u32 bdw_ddi_translations_dp[] = { - 0x00FFFFFF, 0x0007000E, /* DP parameters */ + 0x00FFFFFF, 0x0007000E, 0x00D75FFF, 0x000E000A, 0x00BEFFFF, 0x00140006, 0x80B2CFFF, 0x001B0002, @@ -97,7 +97,7 @@ static const u32 bdw_ddi_translations_dp[] = { }; static const u32 bdw_ddi_translations_fdi[] = { - 0x00FFFFFF, 0x0001000E, /* FDI parameters */ + 0x00FFFFFF, 0x0001000E, 0x00D75FFF, 0x0004000A, 0x00C30FFF, 0x00070006, 0x00AAAFFF, 0x000C0000, -- GitLab From 7fad3594bf2c66843c7d1e09005ff845a94524ab Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 1 Aug 2014 16:19:54 -0300 Subject: [PATCH 0076/5088] drm/i915: remove duplicate register defines cat i915_reg.h | sort | uniq -d | grep define Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ca37febbc2ae..7f9a81087ebc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3756,7 +3756,6 @@ enum punit_power_well { #define PIPE_VSYNC_INTERRUPT_STATUS (1UL<<9) #define PIPE_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) #define PIPE_DPST_EVENT_STATUS (1UL<<7) -#define PIPE_LEGACY_BLC_EVENT_STATUS (1UL<<6) #define PIPE_A_PSR_STATUS_VLV (1UL<<6) #define PIPE_LEGACY_BLC_EVENT_STATUS (1UL<<6) #define PIPE_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) @@ -5431,7 +5430,6 @@ enum punit_power_well { #define VLV_GTLC_ALLOWWAKEERR (1 << 1) #define VLV_GTLC_PW_MEDIA_STATUS_MASK (1 << 5) #define VLV_GTLC_PW_RENDER_STATUS_MASK (1 << 7) -#define VLV_GTLC_SURVIVABILITY_REG 0x130098 #define FORCEWAKE_MT 0xa188 /* multi-threaded */ #define FORCEWAKE_KERNEL 0x1 #define FORCEWAKE_USER 0x2 -- GitLab From 4079b8d1c3e38b6f18fb31e2997fa25276feea07 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 5 Aug 2014 10:39:42 +0100 Subject: [PATCH 0077/5088] drm/i915: Demote the DRRS messages to debug messages While those messages are interesting, there aren't _that_ interesting. We don't need them in the kernel logs by default. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 95b972736733..3b88255d87dc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4429,7 +4429,7 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, } if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) { - DRM_INFO("VBT doesn't support DRRS\n"); + DRM_DEBUG_KMS("VBT doesn't support DRRS\n"); return NULL; } @@ -4437,7 +4437,7 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, (dev, fixed_mode, connector); if (!downclock_mode) { - DRM_INFO("DRRS not supported\n"); + DRM_DEBUG_KMS("DRRS not supported\n"); return NULL; } @@ -4448,7 +4448,7 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, intel_dp->drrs_state.type = dev_priv->vbt.drrs_type; intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR; - DRM_INFO("seamless DRRS supported for eDP panel.\n"); + DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n"); return downclock_mode; } -- GitLab From b2784e151903628a086d2ee12cf943690216cd6c Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 5 Aug 2014 11:29:37 +0100 Subject: [PATCH 0078/5088] drm/i915: Introduce a for_each_intel_encoder() macro Following the established idom, let's provide a macro to iterate through the encoders. spatch helps, once more, for the substitution: @@ iterator name list_for_each_entry; iterator name for_each_intel_encoder; struct intel_encoder * encoder; struct drm_device * dev; @@ -list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { +for_each_intel_encoder(dev, encoder) { ... } I also modified a few call sites by hand where a pointer to mode_config was directly used (to avoid overflowing 80 chars). Signed-off-by: Damien Lespiau [danvet: Wrap paramters correctly in the macro and remove spurious space checkpatch noticed.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +- drivers/gpu/drm/i915/i915_drv.h | 5 +++ drivers/gpu/drm/i915/i915_irq.c | 8 ++-- drivers/gpu/drm/i915/intel_display.c | 59 ++++++++++------------------ drivers/gpu/drm/i915/intel_hdmi.c | 2 +- drivers/gpu/drm/i915/intel_lvds.c | 3 +- 6 files changed, 31 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index aea1a819c775..330caa1ab9f9 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2708,8 +2708,7 @@ static int i9xx_pipe_crc_auto_source(struct drm_device *dev, enum pipe pipe, *source = INTEL_PIPE_CRC_SOURCE_PIPE; drm_modeset_lock_all(dev); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { if (!encoder->base.crtc) continue; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0d7e55f2a8a2..73d2308e2377 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -171,6 +171,11 @@ enum hpd_pin { #define for_each_intel_crtc(dev, intel_crtc) \ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) +#define for_each_intel_encoder(dev, intel_encoder) \ + list_for_each_entry(intel_encoder, \ + &(dev)->mode_config.encoder_list, \ + base.head) + #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ if ((intel_encoder)->base.crtc == (__crtc)) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 379cfb5dc731..87abe8679495 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3522,18 +3522,17 @@ static void cherryview_irq_preinstall(struct drm_device *dev) static void ibx_hpd_irq_setup(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *intel_encoder; u32 hotplug_irqs, hotplug, enabled_irqs = 0; if (HAS_PCH_IBX(dev)) { hotplug_irqs = SDE_HOTPLUG_MASK; - list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + for_each_intel_encoder(dev, intel_encoder) if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin]; } else { hotplug_irqs = SDE_HOTPLUG_MASK_CPT; - list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + for_each_intel_encoder(dev, intel_encoder) if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) enabled_irqs |= hpd_cpt[intel_encoder->hpd_pin]; } @@ -4452,7 +4451,6 @@ static int i965_irq_postinstall(struct drm_device *dev) static void i915_hpd_irq_setup(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *intel_encoder; u32 hotplug_en; @@ -4463,7 +4461,7 @@ static void i915_hpd_irq_setup(struct drm_device *dev) hotplug_en &= ~HOTPLUG_INT_EN_MASK; /* Note HDMI and DP share hotplug bits */ /* enable bits are the same for all generations */ - list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + for_each_intel_encoder(dev, intel_encoder) if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin]; /* Programming the CRT detection parameters tends diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 60ba6962026b..f32a94544940 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6405,7 +6405,6 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, static void ironlake_init_pch_refclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *encoder; u32 val, final; bool has_lvds = false; @@ -6415,8 +6414,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) bool can_ssc = false; /* We need to take the global config into account */ - list_for_each_entry(encoder, &mode_config->encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { switch (encoder->type) { case INTEL_OUTPUT_LVDS: has_panel = true; @@ -6723,11 +6721,10 @@ static void lpt_disable_clkout_dp(struct drm_device *dev) static void lpt_init_pch_refclk(struct drm_device *dev) { - struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *encoder; bool has_vga = false; - list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { + for_each_intel_encoder(dev, encoder) { switch (encoder->type) { case INTEL_OUTPUT_ANALOG: has_vga = true; @@ -9902,8 +9899,7 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev) to_intel_encoder(connector->base.encoder); } - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { encoder->new_crtc = to_intel_crtc(encoder->base.crtc); } @@ -9934,8 +9930,7 @@ static void intel_modeset_commit_output_state(struct drm_device *dev) connector->base.encoder = &connector->new_encoder->base; } - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { encoder->base.crtc = &encoder->new_crtc->base; } @@ -10105,8 +10100,7 @@ static bool check_single_encoder_cloning(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct intel_encoder *source_encoder; - list_for_each_entry(source_encoder, - &dev->mode_config.encoder_list, base.head) { + for_each_intel_encoder(dev, source_encoder) { if (source_encoder->new_crtc != crtc) continue; @@ -10122,8 +10116,7 @@ static bool check_encoder_cloning(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; struct intel_encoder *encoder; - list_for_each_entry(encoder, - &dev->mode_config.encoder_list, base.head) { + for_each_intel_encoder(dev, encoder) { if (encoder->new_crtc != crtc) continue; @@ -10207,8 +10200,7 @@ intel_modeset_pipe_config(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, - base.head) { + for_each_intel_encoder(dev, encoder) { if (&encoder->new_crtc->base != crtc) continue; @@ -10286,8 +10278,7 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, 1 << connector->new_encoder->new_crtc->pipe; } - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { if (encoder->base.crtc == &encoder->new_crtc->base) continue; @@ -10361,8 +10352,7 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) struct intel_crtc *intel_crtc; struct drm_connector *connector; - list_for_each_entry(intel_encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, intel_encoder) { if (!intel_encoder->base.crtc) continue; @@ -10636,8 +10626,7 @@ check_encoder_state(struct drm_device *dev) struct intel_encoder *encoder; struct intel_connector *connector; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { bool enabled = false; bool active = false; enum pipe pipe, tracked_pipe; @@ -10716,8 +10705,7 @@ check_crtc_state(struct drm_device *dev) WARN(crtc->active && !crtc->base.enabled, "active crtc, but not enabled in sw tracking\n"); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { if (encoder->base.crtc != &crtc->base) continue; enabled = true; @@ -10739,8 +10727,7 @@ check_crtc_state(struct drm_device *dev) if (crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) active = crtc->active; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { enum pipe pipe; if (encoder->base.crtc != &crtc->base) continue; @@ -11108,7 +11095,7 @@ static void intel_set_config_restore_state(struct drm_device *dev, } count = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + for_each_intel_encoder(dev, encoder) { encoder->new_crtc = to_intel_crtc(config->save_encoder_crtcs[count++]); } @@ -11267,8 +11254,7 @@ intel_modeset_stage_output_state(struct drm_device *dev, } /* Check for any encoders that needs to be disabled. */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { int num_connectors = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, @@ -11301,9 +11287,7 @@ intel_modeset_stage_output_state(struct drm_device *dev, for_each_intel_crtc(dev, crtc) { crtc->new_enabled = false; - list_for_each_entry(encoder, - &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { if (encoder->new_crtc == crtc) { crtc->new_enabled = true; break; @@ -11340,7 +11324,7 @@ static void disable_crtc_nofb(struct intel_crtc *crtc) connector->new_encoder = NULL; } - list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + for_each_intel_encoder(dev, encoder) { if (encoder->new_crtc == crtc) encoder->new_crtc = NULL; } @@ -11972,8 +11956,7 @@ static int intel_encoder_clones(struct intel_encoder *encoder) int index_mask = 0; int entry = 0; - list_for_each_entry(source_encoder, - &dev->mode_config.encoder_list, base.head) { + for_each_intel_encoder(dev, source_encoder) { if (encoders_cloneable(encoder, source_encoder)) index_mask |= (1 << entry); @@ -12162,7 +12145,7 @@ static void intel_setup_outputs(struct drm_device *dev) intel_edp_psr_init(dev); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + for_each_intel_encoder(dev, encoder) { encoder->base.possible_crtcs = encoder->crtc_mask; encoder->base.possible_clones = intel_encoder_clones(encoder); @@ -13056,8 +13039,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); } - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { pipe = 0; if (encoder->get_hw_state(encoder, &pipe)) { @@ -13121,8 +13103,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, } /* HW state is read out, now we need to sanitize this mess. */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { intel_sanitize_encoder(encoder); } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 5f47d359a991..9169786dbbc3 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -885,7 +885,7 @@ static bool hdmi_12bpc_possible(struct intel_crtc *crtc) if (HAS_GMCH_DISPLAY(dev)) return false; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { + for_each_intel_encoder(dev, encoder) { if (encoder->new_crtc != crtc) continue; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 881361c0f27e..1987491723a5 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -823,8 +823,7 @@ bool intel_is_dual_link_lvds(struct drm_device *dev) struct intel_encoder *encoder; struct intel_lvds_encoder *lvds_encoder; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { + for_each_intel_encoder(dev, encoder) { if (encoder->type == INTEL_OUTPUT_LVDS) { lvds_encoder = to_lvds_encoder(&encoder->base); -- GitLab From 76eebda727c76b5712f6ce75a45a9917d3873a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 Aug 2014 11:26:52 +0530 Subject: [PATCH 0079/5088] drm/i915: Add 180 degree sprite rotation support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sprite planes (in fact all display planes starting from gen4) support 180 degree rotation. Add the relevant low level bits to the sprite code to make use of that feature. The upper layers are not yet plugged in. v2: HSW handles the rotated buffer offset automagically v3: BDW also handles the rotated buffer offset automagically Testcase: igt/kms_rotation_crc Cc: dri-devel@lists.freedesktop.org Signed-off-by: Ville Syrjälä Signed-off-by: Sagar Kamble Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_sprite.c | 38 +++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7f9a81087ebc..5ebac620bbcd 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4218,6 +4218,7 @@ enum punit_power_well { #define DVS_YUV_ORDER_UYVY (1<<16) #define DVS_YUV_ORDER_YVYU (2<<16) #define DVS_YUV_ORDER_VYUY (3<<16) +#define DVS_ROTATE_180 (1<<15) #define DVS_DEST_KEY (1<<2) #define DVS_TRICKLE_FEED_DISABLE (1<<14) #define DVS_TILED (1<<10) @@ -4288,6 +4289,7 @@ enum punit_power_well { #define SPRITE_YUV_ORDER_UYVY (1<<16) #define SPRITE_YUV_ORDER_YVYU (2<<16) #define SPRITE_YUV_ORDER_VYUY (3<<16) +#define SPRITE_ROTATE_180 (1<<15) #define SPRITE_TRICKLE_FEED_DISABLE (1<<14) #define SPRITE_INT_GAMMA_ENABLE (1<<13) #define SPRITE_TILED (1<<10) @@ -4361,6 +4363,7 @@ enum punit_power_well { #define SP_YUV_ORDER_UYVY (1<<16) #define SP_YUV_ORDER_YVYU (2<<16) #define SP_YUV_ORDER_VYUY (3<<16) +#define SP_ROTATE_180 (1<<15) #define SP_TILED (1<<10) #define _SPALINOFF (VLV_DISPLAY_BASE + 0x72184) #define _SPASTRIDE (VLV_DISPLAY_BASE + 0x72188) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3198de3007be..b63df4416301 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -448,6 +448,7 @@ struct intel_plane { unsigned int crtc_w, crtc_h; uint32_t src_x, src_y; uint32_t src_w, src_h; + unsigned int rotation; /* 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 d34a5696ffb6..f4d10c4b2781 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -164,6 +164,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, sprctl &= ~SP_PIXFORMAT_MASK; sprctl &= ~SP_YUV_BYTE_ORDER_MASK; sprctl &= ~SP_TILED; + sprctl &= ~SP_ROTATE_180; switch (fb->pixel_format) { case DRM_FORMAT_YUYV: @@ -236,6 +237,14 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, fb->pitches[0]); linear_offset -= sprsurf_offset; + if (intel_plane->rotation == BIT(DRM_ROTATE_180)) { + sprctl |= SP_ROTATE_180; + + x += src_w; + y += src_h; + linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; + } + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); intel_update_primary_plane(intel_crtc); @@ -365,6 +374,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, sprctl &= ~SPRITE_RGB_ORDER_RGBX; sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK; sprctl &= ~SPRITE_TILED; + sprctl &= ~SPRITE_ROTATE_180; switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: @@ -427,6 +437,18 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, pixel_size, fb->pitches[0]); linear_offset -= sprsurf_offset; + if (intel_plane->rotation == BIT(DRM_ROTATE_180)) { + sprctl |= SPRITE_ROTATE_180; + + /* HSW and BDW does this automagically in hardware */ + if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { + x += src_w; + y += src_h; + linear_offset += src_h * fb->pitches[0] + + src_w * pixel_size; + } + } + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); intel_update_primary_plane(intel_crtc); @@ -572,6 +594,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, dvscntr &= ~DVS_RGB_ORDER_XBGR; dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK; dvscntr &= ~DVS_TILED; + dvscntr &= ~DVS_ROTATE_180; switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: @@ -629,6 +652,14 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, pixel_size, fb->pitches[0]); linear_offset -= dvssurf_offset; + if (intel_plane->rotation == BIT(DRM_ROTATE_180)) { + dvscntr |= DVS_ROTATE_180; + + x += src_w; + y += src_h; + linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; + } + atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); intel_update_primary_plane(intel_crtc); @@ -896,6 +927,9 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, max_scale = intel_plane->max_downscale << 16; min_scale = intel_plane->can_scale ? 1 : (1 << 16); + drm_rect_rotate(&src, fb->width << 16, fb->height << 16, + intel_plane->rotation); + hscale = drm_rect_calc_hscale_relaxed(&src, &dst, min_scale, max_scale); BUG_ON(hscale < 0); @@ -934,6 +968,9 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, drm_rect_width(&dst) * hscale - drm_rect_width(&src), drm_rect_height(&dst) * vscale - drm_rect_height(&src)); + drm_rect_rotate_inv(&src, fb->width << 16, fb->height << 16, + intel_plane->rotation); + /* sanity check to make sure the src viewport wasn't enlarged */ WARN_ON(src.x1 < (int) src_x || src.y1 < (int) src_y || @@ -1311,6 +1348,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) intel_plane->pipe = pipe; intel_plane->plane = plane; + intel_plane->rotation = BIT(DRM_ROTATE_0); possible_crtcs = (1 << pipe); ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, &intel_plane_funcs, -- GitLab From e57465f35192246b6587c3bc89b5ed96a8fdfb00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 Aug 2014 11:26:53 +0530 Subject: [PATCH 0080/5088] drm/i915: Make intel_plane_restore() return an error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Propagate the error from intel_update_plane() up through intel_plane_restore() to the caller. This will be used for rollback purposes when setting properties fails. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_sprite.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b63df4416301..79782094c8f9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1086,7 +1086,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); void intel_flush_primary_plane(struct drm_i915_private *dev_priv, enum plane plane); -void intel_plane_restore(struct drm_plane *plane); +int intel_plane_restore(struct drm_plane *plane); void intel_plane_disable(struct drm_plane *plane); int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index f4d10c4b2781..611826209c99 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1218,18 +1218,18 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, return ret; } -void intel_plane_restore(struct drm_plane *plane) +int intel_plane_restore(struct drm_plane *plane) { struct intel_plane *intel_plane = to_intel_plane(plane); if (!plane->crtc || !plane->fb) - return; + return 0; - intel_update_plane(plane, plane->crtc, plane->fb, - intel_plane->crtc_x, intel_plane->crtc_y, - intel_plane->crtc_w, intel_plane->crtc_h, - intel_plane->src_x, intel_plane->src_y, - intel_plane->src_w, intel_plane->src_h); + return intel_update_plane(plane, plane->crtc, plane->fb, + intel_plane->crtc_x, intel_plane->crtc_y, + intel_plane->crtc_w, intel_plane->crtc_h, + intel_plane->src_x, intel_plane->src_y, + intel_plane->src_w, intel_plane->src_h); } void intel_plane_disable(struct drm_plane *plane) -- GitLab From 2a297cce2e775812e9d6ca84c3ab92cee5c38e25 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Tue, 5 Aug 2014 11:26:54 +0530 Subject: [PATCH 0081/5088] drm: Add rotation_property to mode_config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sonika Jindal Reviewed-by: Ville Syrjälä Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- include/drm/drm_crtc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f1105d0da059..62f73bdbcc47 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -821,6 +821,7 @@ struct drm_mode_config { struct drm_property *dpms_property; struct drm_property *path_property; struct drm_property *plane_type_property; + struct drm_property *rotation_property; /* DVI-I properties */ struct drm_property *dvi_i_subconnector_property; -- GitLab From 7ed6eeeec60c98ec824e27a5052aa249d98bd63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 Aug 2014 11:26:55 +0530 Subject: [PATCH 0082/5088] drm/i915: Add rotation property for sprites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sprite planes support 180 degree rotation. The lower layers are now in place, so hook in the standard rotation property to expose the feature to the users. v2: Moving rotation_property to mode_config Cc: dri-devel@lists.freedesktop.org Signed-off-by: Ville Syrjälä Signed-off-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 41 ++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 611826209c99..0bdb00b7c59c 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1218,6 +1218,30 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, return ret; } +static int intel_plane_set_property(struct drm_plane *plane, + struct drm_property *prop, + uint64_t val) +{ + struct drm_device *dev = plane->dev; + struct intel_plane *intel_plane = to_intel_plane(plane); + uint64_t old_val; + int ret = -ENOENT; + + if (prop == dev->mode_config.rotation_property) { + /* exactly one rotation angle please */ + if (hweight32(val & 0xf) != 1) + return -EINVAL; + + old_val = intel_plane->rotation; + intel_plane->rotation = val; + ret = intel_plane_restore(plane); + if (ret) + intel_plane->rotation = old_val; + } + + return ret; +} + int intel_plane_restore(struct drm_plane *plane) { struct intel_plane *intel_plane = to_intel_plane(plane); @@ -1244,6 +1268,7 @@ static const struct drm_plane_funcs intel_plane_funcs = { .update_plane = intel_update_plane, .disable_plane = intel_disable_plane, .destroy = intel_destroy_plane, + .set_property = intel_plane_set_property, }; static uint32_t ilk_plane_formats[] = { @@ -1354,8 +1379,22 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) &intel_plane_funcs, plane_formats, num_plane_formats, false); - if (ret) + if (ret) { kfree(intel_plane); + goto out; + } + + if (!dev->mode_config.rotation_property) + dev->mode_config.rotation_property = + drm_mode_create_rotation_property(dev, + BIT(DRM_ROTATE_0) | + BIT(DRM_ROTATE_180)); + + if (dev->mode_config.rotation_property) + drm_object_attach_property(&intel_plane->base.base, + dev->mode_config.rotation_property, + intel_plane->rotation); + out: return ret; } -- GitLab From 9783de20967a59d7627772bf77fc8066c47bef79 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Tue, 5 Aug 2014 11:26:57 +0530 Subject: [PATCH 0083/5088] drm: Resetting rotation property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reset rotation property to 0. v2: Resetting after disabling the plane Signed-off-by: Sonika Jindal Reviewed-by: Ville Syrjälä Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3144db9dc0f1..d139eddb3d61 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -345,10 +345,17 @@ 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) + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) drm_plane_force_disable(plane); + if (dev->mode_config.rotation_property) { + drm_object_property_set_value(&plane->base, + dev->mode_config.rotation_property, + BIT(DRM_ROTATE_0)); + } + } + for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; struct drm_crtc *crtc = mode_set->crtc; -- GitLab From 0a56067469bde6662ce7c89a3d290171f878bac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 11 Jun 2014 16:51:18 +0300 Subject: [PATCH 0084/5088] drm/i915: Fill out the FWx watermark register defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add defines for all the watermark registers on modernish gmch platforms. VLV has increased the number of bits available for certain watermaks so expand the masks appropriately. Also vlv and chv have added some extra FW registers. Not sure what happened on chv because a new register called FW9 is now at the offset where FW7 was on vlv, while FW7 and FW8 (another new register) have been moved off somewhere else. Oh well, well just need two defines for FW7 then. v2: Fix DSPHOWM1 offset (Paulo) Reviewed-by: Paulo Zanoni Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 138 ++++++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_pm.c | 11 ++- 2 files changed, 130 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5ebac620bbcd..a87eb18b4c90 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3865,28 +3865,136 @@ enum punit_power_well { #define DSPARB_BEND_SHIFT 9 /* on 855 */ #define DSPARB_AEND_SHIFT 0 +/* pnv/gen4/g4x/vlv/chv */ #define DSPFW1 (dev_priv->info.display_mmio_offset + 0x70034) -#define DSPFW_SR_SHIFT 23 -#define DSPFW_SR_MASK (0x1ff<<23) -#define DSPFW_CURSORB_SHIFT 16 -#define DSPFW_CURSORB_MASK (0x3f<<16) -#define DSPFW_PLANEB_SHIFT 8 -#define DSPFW_PLANEB_MASK (0x7f<<8) -#define DSPFW_PLANEA_MASK (0x7f) +#define DSPFW_SR_SHIFT 23 +#define DSPFW_SR_MASK (0x1ff<<23) +#define DSPFW_CURSORB_SHIFT 16 +#define DSPFW_CURSORB_MASK (0x3f<<16) +#define DSPFW_PLANEB_SHIFT 8 +#define DSPFW_PLANEB_MASK (0x7f<<8) +#define DSPFW_PLANEB_MASK_VLV (0xff<<8) /* vlv/chv */ +#define DSPFW_PLANEA_SHIFT 0 +#define DSPFW_PLANEA_MASK (0x7f<<0) +#define DSPFW_PLANEA_MASK_VLV (0xff<<0) /* vlv/chv */ #define DSPFW2 (dev_priv->info.display_mmio_offset + 0x70038) -#define DSPFW_CURSORA_MASK 0x00003f00 -#define DSPFW_CURSORA_SHIFT 8 -#define DSPFW_PLANEC_MASK (0x7f) +#define DSPFW_FBC_SR_EN (1<<31) /* g4x */ +#define DSPFW_FBC_SR_SHIFT 28 +#define DSPFW_FBC_SR_MASK (0x7<<28) /* g4x */ +#define DSPFW_FBC_HPLL_SR_SHIFT 24 +#define DSPFW_FBC_HPLL_SR_MASK (0xf<<24) /* g4x */ +#define DSPFW_SPRITEB_SHIFT (16) +#define DSPFW_SPRITEB_MASK (0x7f<<16) /* g4x */ +#define DSPFW_SPRITEB_MASK_VLV (0xff<<16) /* vlv/chv */ +#define DSPFW_CURSORA_SHIFT 8 +#define DSPFW_CURSORA_MASK (0x3f<<8) +#define DSPFW_PLANEC_SHIFT_OLD 0 +#define DSPFW_PLANEC_MASK_OLD (0x7f<<0) /* pre-gen4 sprite C */ +#define DSPFW_SPRITEA_SHIFT 0 +#define DSPFW_SPRITEA_MASK (0x7f<<0) /* g4x */ +#define DSPFW_SPRITEA_MASK_VLV (0xff<<0) /* vlv/chv */ #define DSPFW3 (dev_priv->info.display_mmio_offset + 0x7003c) -#define DSPFW_HPLL_SR_EN (1<<31) -#define DSPFW_CURSOR_SR_SHIFT 24 +#define DSPFW_HPLL_SR_EN (1<<31) #define PINEVIEW_SELF_REFRESH_EN (1<<30) +#define DSPFW_CURSOR_SR_SHIFT 24 #define DSPFW_CURSOR_SR_MASK (0x3f<<24) #define DSPFW_HPLL_CURSOR_SHIFT 16 #define DSPFW_HPLL_CURSOR_MASK (0x3f<<16) -#define DSPFW_HPLL_SR_MASK (0x1ff) -#define DSPFW4 (dev_priv->info.display_mmio_offset + 0x70070) -#define DSPFW7 (dev_priv->info.display_mmio_offset + 0x7007c) +#define DSPFW_HPLL_SR_SHIFT 0 +#define DSPFW_HPLL_SR_MASK (0x1ff<<0) + +/* vlv/chv */ +#define DSPFW4 (VLV_DISPLAY_BASE + 0x70070) +#define DSPFW_SPRITEB_WM1_SHIFT 16 +#define DSPFW_SPRITEB_WM1_MASK (0xff<<16) +#define DSPFW_CURSORA_WM1_SHIFT 8 +#define DSPFW_CURSORA_WM1_MASK (0x3f<<8) +#define DSPFW_SPRITEA_WM1_SHIFT 0 +#define DSPFW_SPRITEA_WM1_MASK (0xff<<0) +#define DSPFW5 (VLV_DISPLAY_BASE + 0x70074) +#define DSPFW_PLANEB_WM1_SHIFT 24 +#define DSPFW_PLANEB_WM1_MASK (0xff<<24) +#define DSPFW_PLANEA_WM1_SHIFT 16 +#define DSPFW_PLANEA_WM1_MASK (0xff<<16) +#define DSPFW_CURSORB_WM1_SHIFT 8 +#define DSPFW_CURSORB_WM1_MASK (0x3f<<8) +#define DSPFW_CURSOR_SR_WM1_SHIFT 0 +#define DSPFW_CURSOR_SR_WM1_MASK (0x3f<<0) +#define DSPFW6 (VLV_DISPLAY_BASE + 0x70078) +#define DSPFW_SR_WM1_SHIFT 0 +#define DSPFW_SR_WM1_MASK (0x1ff<<0) +#define DSPFW7 (VLV_DISPLAY_BASE + 0x7007c) +#define DSPFW7_CHV (VLV_DISPLAY_BASE + 0x700b4) /* wtf #1? */ +#define DSPFW_SPRITED_WM1_SHIFT 24 +#define DSPFW_SPRITED_WM1_MASK (0xff<<24) +#define DSPFW_SPRITED_SHIFT 16 +#define DSPFW_SPRITED_MASK (0xff<<16) +#define DSPFW_SPRITEC_WM1_SHIFT 8 +#define DSPFW_SPRITEC_WM1_MASK (0xff<<8) +#define DSPFW_SPRITEC_SHIFT 0 +#define DSPFW_SPRITEC_MASK (0xff<<0) +#define DSPFW8_CHV (VLV_DISPLAY_BASE + 0x700b8) +#define DSPFW_SPRITEF_WM1_SHIFT 24 +#define DSPFW_SPRITEF_WM1_MASK (0xff<<24) +#define DSPFW_SPRITEF_SHIFT 16 +#define DSPFW_SPRITEF_MASK (0xff<<16) +#define DSPFW_SPRITEE_WM1_SHIFT 8 +#define DSPFW_SPRITEE_WM1_MASK (0xff<<8) +#define DSPFW_SPRITEE_SHIFT 0 +#define DSPFW_SPRITEE_MASK (0xff<<0) +#define DSPFW9_CHV (VLV_DISPLAY_BASE + 0x7007c) /* wtf #2? */ +#define DSPFW_PLANEC_WM1_SHIFT 24 +#define DSPFW_PLANEC_WM1_MASK (0xff<<24) +#define DSPFW_PLANEC_SHIFT 16 +#define DSPFW_PLANEC_MASK (0xff<<16) +#define DSPFW_CURSORC_WM1_SHIFT 8 +#define DSPFW_CURSORC_WM1_MASK (0x3f<<16) +#define DSPFW_CURSORC_SHIFT 0 +#define DSPFW_CURSORC_MASK (0x3f<<0) + +/* vlv/chv high order bits */ +#define DSPHOWM (VLV_DISPLAY_BASE + 0x70064) +#define DSPFW_SR_HI_SHIFT 24 +#define DSPFW_SR_HI_MASK (1<<24) +#define DSPFW_SPRITEF_HI_SHIFT 23 +#define DSPFW_SPRITEF_HI_MASK (1<<23) +#define DSPFW_SPRITEE_HI_SHIFT 22 +#define DSPFW_SPRITEE_HI_MASK (1<<22) +#define DSPFW_PLANEC_HI_SHIFT 21 +#define DSPFW_PLANEC_HI_MASK (1<<21) +#define DSPFW_SPRITED_HI_SHIFT 20 +#define DSPFW_SPRITED_HI_MASK (1<<20) +#define DSPFW_SPRITEC_HI_SHIFT 16 +#define DSPFW_SPRITEC_HI_MASK (1<<16) +#define DSPFW_PLANEB_HI_SHIFT 12 +#define DSPFW_PLANEB_HI_MASK (1<<12) +#define DSPFW_SPRITEB_HI_SHIFT 8 +#define DSPFW_SPRITEB_HI_MASK (1<<8) +#define DSPFW_SPRITEA_HI_SHIFT 4 +#define DSPFW_SPRITEA_HI_MASK (1<<4) +#define DSPFW_PLANEA_HI_SHIFT 0 +#define DSPFW_PLANEA_HI_MASK (1<<0) +#define DSPHOWM1 (VLV_DISPLAY_BASE + 0x70068) +#define DSPFW_SR_WM1_HI_SHIFT 24 +#define DSPFW_SR_WM1_HI_MASK (1<<24) +#define DSPFW_SPRITEF_WM1_HI_SHIFT 23 +#define DSPFW_SPRITEF_WM1_HI_MASK (1<<23) +#define DSPFW_SPRITEE_WM1_HI_SHIFT 22 +#define DSPFW_SPRITEE_WM1_HI_MASK (1<<22) +#define DSPFW_PLANEC_WM1_HI_SHIFT 21 +#define DSPFW_PLANEC_WM1_HI_MASK (1<<21) +#define DSPFW_SPRITED_WM1_HI_SHIFT 20 +#define DSPFW_SPRITED_WM1_HI_MASK (1<<20) +#define DSPFW_SPRITEC_WM1_HI_SHIFT 16 +#define DSPFW_SPRITEC_WM1_HI_MASK (1<<16) +#define DSPFW_PLANEB_WM1_HI_SHIFT 12 +#define DSPFW_PLANEB_WM1_HI_MASK (1<<12) +#define DSPFW_SPRITEB_WM1_HI_SHIFT 8 +#define DSPFW_SPRITEB_WM1_HI_MASK (1<<8) +#define DSPFW_SPRITEA_WM1_HI_SHIFT 4 +#define DSPFW_SPRITEA_WM1_HI_MASK (1<<4) +#define DSPFW_PLANEA_WM1_HI_SHIFT 0 +#define DSPFW_PLANEA_WM1_HI_MASK (1<<0) /* drain latency register values*/ #define DRAIN_LATENCY_PRECISION_32 32 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ab80df2909e0..0f9164d854de 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1400,7 +1400,7 @@ static void valleyview_update_wm(struct drm_crtc *crtc) (plane_sr << DSPFW_SR_SHIFT) | (cursorb_wm << DSPFW_CURSORB_SHIFT) | (planeb_wm << DSPFW_PLANEB_SHIFT) | - planea_wm); + (planea_wm << DSPFW_PLANEA_SHIFT)); I915_WRITE(DSPFW2, (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) | (cursora_wm << DSPFW_CURSORA_SHIFT)); @@ -1457,7 +1457,7 @@ static void g4x_update_wm(struct drm_crtc *crtc) (plane_sr << DSPFW_SR_SHIFT) | (cursorb_wm << DSPFW_CURSORB_SHIFT) | (planeb_wm << DSPFW_PLANEB_SHIFT) | - planea_wm); + (planea_wm << DSPFW_PLANEA_SHIFT)); I915_WRITE(DSPFW2, (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) | (cursora_wm << DSPFW_CURSORA_SHIFT)); @@ -1531,8 +1531,11 @@ static void i965_update_wm(struct drm_crtc *unused_crtc) /* 965 has limitations... */ I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | - (8 << 16) | (8 << 8) | (8 << 0)); - I915_WRITE(DSPFW2, (8 << 8) | (8 << 0)); + (8 << DSPFW_CURSORB_SHIFT) | + (8 << DSPFW_PLANEB_SHIFT) | + (8 << DSPFW_PLANEA_SHIFT)); + I915_WRITE(DSPFW2, (8 << DSPFW_CURSORA_SHIFT) | + (8 << DSPFW_PLANEC_SHIFT_OLD)); /* update cursor SR watermark */ I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); -- GitLab From 1abc4dc7e2ca7886b6b06bcf2ff1451702c83f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 26 Jun 2014 17:02:37 +0300 Subject: [PATCH 0085/5088] drm/i915: Parametrize VLV_DDL registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VLV/CHV DDL registers are uniform, and neatly enough the register offsets are sane so we can easily unify them to a single set of defines and just pass the pipe as the parameter to compute the register offset. Note that we now fill out the drain latency for pipe C on CHV which we didn't do before. The rest of the pipe C watermarks are still untouched but that will be remedied later by adding a proper cherryview_update_wm() function. v2: Add a note about CHV pipe C changes (Paulo) Reviewed-by: Paulo Zanoni Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 54 ++++++++------------------------- drivers/gpu/drm/i915/intel_pm.c | 52 ++++++++++++++----------------- 2 files changed, 36 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a87eb18b4c90..fbdb08f4cd76 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3999,47 +3999,19 @@ enum punit_power_well { /* drain latency register values*/ #define DRAIN_LATENCY_PRECISION_32 32 #define DRAIN_LATENCY_PRECISION_64 64 -#define VLV_DDL1 (VLV_DISPLAY_BASE + 0x70050) -#define DDL_CURSORA_PRECISION_64 (1<<31) -#define DDL_CURSORA_PRECISION_32 (0<<31) -#define DDL_CURSORA_SHIFT 24 -#define DDL_SPRITEB_PRECISION_64 (1<<23) -#define DDL_SPRITEB_PRECISION_32 (0<<23) -#define DDL_SPRITEB_SHIFT 16 -#define DDL_SPRITEA_PRECISION_64 (1<<15) -#define DDL_SPRITEA_PRECISION_32 (0<<15) -#define DDL_SPRITEA_SHIFT 8 -#define DDL_PLANEA_PRECISION_64 (1<<7) -#define DDL_PLANEA_PRECISION_32 (0<<7) -#define DDL_PLANEA_SHIFT 0 - -#define VLV_DDL2 (VLV_DISPLAY_BASE + 0x70054) -#define DDL_CURSORB_PRECISION_64 (1<<31) -#define DDL_CURSORB_PRECISION_32 (0<<31) -#define DDL_CURSORB_SHIFT 24 -#define DDL_SPRITED_PRECISION_64 (1<<23) -#define DDL_SPRITED_PRECISION_32 (0<<23) -#define DDL_SPRITED_SHIFT 16 -#define DDL_SPRITEC_PRECISION_64 (1<<15) -#define DDL_SPRITEC_PRECISION_32 (0<<15) -#define DDL_SPRITEC_SHIFT 8 -#define DDL_PLANEB_PRECISION_64 (1<<7) -#define DDL_PLANEB_PRECISION_32 (0<<7) -#define DDL_PLANEB_SHIFT 0 - -#define VLV_DDL3 (VLV_DISPLAY_BASE + 0x70058) -#define DDL_CURSORC_PRECISION_64 (1<<31) -#define DDL_CURSORC_PRECISION_32 (0<<31) -#define DDL_CURSORC_SHIFT 24 -#define DDL_SPRITEF_PRECISION_64 (1<<23) -#define DDL_SPRITEF_PRECISION_32 (0<<23) -#define DDL_SPRITEF_SHIFT 16 -#define DDL_SPRITEE_PRECISION_64 (1<<15) -#define DDL_SPRITEE_PRECISION_32 (0<<15) -#define DDL_SPRITEE_SHIFT 8 -#define DDL_PLANEC_PRECISION_64 (1<<7) -#define DDL_PLANEC_PRECISION_32 (0<<7) -#define DDL_PLANEC_SHIFT 0 +#define VLV_DDL(pipe) (VLV_DISPLAY_BASE + 0x70050 + 4 * (pipe)) +#define DDL_CURSOR_PRECISION_64 (1<<31) +#define DDL_CURSOR_PRECISION_32 (0<<31) +#define DDL_CURSOR_SHIFT 24 +#define DDL_SPRITE1_PRECISION_64 (1<<23) +#define DDL_SPRITE1_PRECISION_32 (0<<23) +#define DDL_SPRITE1_SHIFT 16 +#define DDL_SPRITE0_PRECISION_64 (1<<15) +#define DDL_SPRITE0_PRECISION_32 (0<<15) +#define DDL_SPRITE0_SHIFT 8 +#define DDL_PLANE_PRECISION_64 (1<<7) +#define DDL_PLANE_PRECISION_32 (0<<7) +#define DDL_PLANE_SHIFT 0 /* FIFO watermark sizes etc */ #define G4X_FIFO_LINE_SIZE 64 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0f9164d854de..2573c6967559 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1313,35 +1313,29 @@ static bool vlv_compute_drain_latency(struct drm_device *dev, static void vlv_update_drain_latency(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int planea_prec, planea_dl, planeb_prec, planeb_dl; - int cursora_prec, cursora_dl, cursorb_prec, cursorb_dl; - int plane_prec_mult, cursor_prec_mult; /* Precision multiplier is - either 16 or 32 */ - - /* For plane A, Cursor A */ - if (vlv_compute_drain_latency(dev, 0, &plane_prec_mult, &planea_dl, - &cursor_prec_mult, &cursora_dl)) { - cursora_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ? - DDL_CURSORA_PRECISION_32 : DDL_CURSORA_PRECISION_64; - planea_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ? - DDL_PLANEA_PRECISION_32 : DDL_PLANEA_PRECISION_64; - - I915_WRITE(VLV_DDL1, cursora_prec | - (cursora_dl << DDL_CURSORA_SHIFT) | - planea_prec | planea_dl); - } - - /* For plane B, Cursor B */ - if (vlv_compute_drain_latency(dev, 1, &plane_prec_mult, &planeb_dl, - &cursor_prec_mult, &cursorb_dl)) { - cursorb_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ? - DDL_CURSORB_PRECISION_32 : DDL_CURSORB_PRECISION_64; - planeb_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ? - DDL_PLANEB_PRECISION_32 : DDL_PLANEB_PRECISION_64; - - I915_WRITE(VLV_DDL2, cursorb_prec | - (cursorb_dl << DDL_CURSORB_SHIFT) | - planeb_prec | planeb_dl); + enum pipe pipe; + + for_each_pipe(pipe) { + int plane_prec, plane_dl; + int cursor_prec, cursor_dl; + int plane_prec_mult, cursor_prec_mult; + + if (!vlv_compute_drain_latency(dev, pipe, &plane_prec_mult, &plane_dl, + &cursor_prec_mult, &cursor_dl)) + continue; + + /* + * FIXME CHV spec still lists 16 and 32 as the precision + * values. Need to figure out if spec is outdated or what. + */ + cursor_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_64) ? + DDL_CURSOR_PRECISION_64 : DDL_CURSOR_PRECISION_32; + plane_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_64) ? + DDL_PLANE_PRECISION_64 : DDL_PLANE_PRECISION_32; + + I915_WRITE(VLV_DDL(pipe), cursor_prec | + (cursor_dl << DDL_CURSOR_SHIFT) | + plane_prec | (plane_dl << DDL_PLANE_SHIFT)); } } -- GitLab From 41aad816d7061f6cc3d92f39fc655f034bbfb1c0 Mon Sep 17 00:00:00 2001 From: Gajanan Bhat Date: Wed, 16 Jul 2014 18:24:03 +0530 Subject: [PATCH 0086/5088] drm/i915: Update DDL only for current CRTC Instead of looping through all CRTCs, update DDL for current CRTC for which watermark is being updated. CHV is confirmed to have precision of 32/64 which is same as VLV. Reviewed-by: Imre Deak Signed-off-by: Gajanan Bhat Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2573c6967559..0feeae845f12 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1310,24 +1310,17 @@ static bool vlv_compute_drain_latency(struct drm_device *dev, * latency value. */ -static void vlv_update_drain_latency(struct drm_device *dev) +static void vlv_update_drain_latency(struct drm_crtc *crtc) { + struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe pipe; - - for_each_pipe(pipe) { - int plane_prec, plane_dl; - int cursor_prec, cursor_dl; - int plane_prec_mult, cursor_prec_mult; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + int plane_prec, plane_dl; + int cursor_prec, cursor_dl; + int plane_prec_mult, cursor_prec_mult; - if (!vlv_compute_drain_latency(dev, pipe, &plane_prec_mult, &plane_dl, - &cursor_prec_mult, &cursor_dl)) - continue; - - /* - * FIXME CHV spec still lists 16 and 32 as the precision - * values. Need to figure out if spec is outdated or what. - */ + if (vlv_compute_drain_latency(dev, pipe, &plane_prec_mult, &plane_dl, + &cursor_prec_mult, &cursor_dl)) { cursor_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_64) ? DDL_CURSOR_PRECISION_64 : DDL_CURSOR_PRECISION_32; plane_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_64) ? @@ -1352,7 +1345,7 @@ static void valleyview_update_wm(struct drm_crtc *crtc) unsigned int enabled = 0; bool cxsr_enabled; - vlv_update_drain_latency(dev); + vlv_update_drain_latency(crtc); if (g4x_compute_wm0(dev, PIPE_A, &valleyview_wm_info, latency_ns, -- GitLab From 3c2777fd2faa5d1c1d5867baa086f2fd8b05479e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 26 Jun 2014 17:03:06 +0300 Subject: [PATCH 0087/5088] drm/i915: Add cherryview_update_wm() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV has a third pipe so we need to compute the watermarks for its planes. Add cherryview_update_wm() to do just that. v2: Rebase on top of Imre's cxsr changes v3: Pass crtc to vlv_update_drain_latency() Reviewed-by: Paulo Zanoni Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 81 ++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0feeae845f12..da43e30ad60b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1399,6 +1399,85 @@ static void valleyview_update_wm(struct drm_crtc *crtc) intel_set_memory_cxsr(dev_priv, true); } +static void cherryview_update_wm(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + static const int sr_latency_ns = 12000; + struct drm_i915_private *dev_priv = dev->dev_private; + int planea_wm, planeb_wm, planec_wm; + int cursora_wm, cursorb_wm, cursorc_wm; + int plane_sr, cursor_sr; + int ignore_plane_sr, ignore_cursor_sr; + unsigned int enabled = 0; + bool cxsr_enabled; + + vlv_update_drain_latency(crtc); + + if (g4x_compute_wm0(dev, PIPE_A, + &valleyview_wm_info, latency_ns, + &valleyview_cursor_wm_info, latency_ns, + &planea_wm, &cursora_wm)) + enabled |= 1 << PIPE_A; + + if (g4x_compute_wm0(dev, PIPE_B, + &valleyview_wm_info, latency_ns, + &valleyview_cursor_wm_info, latency_ns, + &planeb_wm, &cursorb_wm)) + enabled |= 1 << PIPE_B; + + if (g4x_compute_wm0(dev, PIPE_C, + &valleyview_wm_info, latency_ns, + &valleyview_cursor_wm_info, latency_ns, + &planec_wm, &cursorc_wm)) + enabled |= 1 << PIPE_C; + + if (single_plane_enabled(enabled) && + g4x_compute_srwm(dev, ffs(enabled) - 1, + sr_latency_ns, + &valleyview_wm_info, + &valleyview_cursor_wm_info, + &plane_sr, &ignore_cursor_sr) && + g4x_compute_srwm(dev, ffs(enabled) - 1, + 2*sr_latency_ns, + &valleyview_wm_info, + &valleyview_cursor_wm_info, + &ignore_plane_sr, &cursor_sr)) { + cxsr_enabled = true; + } else { + cxsr_enabled = false; + intel_set_memory_cxsr(dev_priv, false); + plane_sr = cursor_sr = 0; + } + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, " + "B: plane=%d, cursor=%d, C: plane=%d, cursor=%d, " + "SR: plane=%d, cursor=%d\n", + planea_wm, cursora_wm, + planeb_wm, cursorb_wm, + planec_wm, cursorc_wm, + plane_sr, cursor_sr); + + I915_WRITE(DSPFW1, + (plane_sr << DSPFW_SR_SHIFT) | + (cursorb_wm << DSPFW_CURSORB_SHIFT) | + (planeb_wm << DSPFW_PLANEB_SHIFT) | + (planea_wm << DSPFW_PLANEA_SHIFT)); + I915_WRITE(DSPFW2, + (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) | + (cursora_wm << DSPFW_CURSORA_SHIFT)); + I915_WRITE(DSPFW3, + (I915_READ(DSPFW3) & ~DSPFW_CURSOR_SR_MASK) | + (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); + I915_WRITE(DSPFW9_CHV, + (I915_READ(DSPFW9_CHV) & ~(DSPFW_PLANEC_MASK | + DSPFW_CURSORC_MASK)) | + (planec_wm << DSPFW_PLANEC_SHIFT) | + (cursorc_wm << DSPFW_CURSORC_SHIFT)); + + if (cxsr_enabled) + intel_set_memory_cxsr(dev_priv, true); +} + static void g4x_update_wm(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -7119,7 +7198,7 @@ void intel_init_pm(struct drm_device *dev) else if (INTEL_INFO(dev)->gen == 8) dev_priv->display.init_clock_gating = gen8_init_clock_gating; } else if (IS_CHERRYVIEW(dev)) { - dev_priv->display.update_wm = valleyview_update_wm; + dev_priv->display.update_wm = cherryview_update_wm; dev_priv->display.init_clock_gating = cherryview_init_clock_gating; } else if (IS_VALLEYVIEW(dev)) { -- GitLab From 3dd7b97458e8aa2d8985b46622d226fa635071e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 Jun 2014 19:49:57 +0300 Subject: [PATCH 0088/5088] drm/i915: Hack to tie both common lanes together on chv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It looks like frobbing the cmnreset line on pne PHY disturbs the other PHY on chv. The result is a black screen. On HDMI it's just a flash of black, but DP usually falls over and can't get back up. As a workaround set up the power domains so that both common lane wells power up and down together. I also tried leaving the cmnreset deasserted even the if the power well goes down but that didn't seem acceptable to the PHY. Reviewed-by: Rafael Barbalho Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index da43e30ad60b..aaae22815965 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6877,13 +6877,23 @@ static struct i915_power_well chv_power_wells[] = { #endif { .name = "dpio-common-bc", - .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS, + /* + * XXX: cmnreset for one PHY seems to disturb the other. + * As a workaround keep both powered on at the same + * time for now. + */ + .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS | CHV_DPIO_CMN_D_POWER_DOMAINS, .data = PUNIT_POWER_WELL_DPIO_CMN_BC, .ops = &chv_dpio_cmn_power_well_ops, }, { .name = "dpio-common-d", - .domains = CHV_DPIO_CMN_D_POWER_DOMAINS, + /* + * XXX: cmnreset for one PHY seems to disturb the other. + * As a workaround keep both powered on at the same + * time for now. + */ + .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS | CHV_DPIO_CMN_D_POWER_DOMAINS, .data = PUNIT_POWER_WELL_DPIO_CMN_D, .ops = &chv_dpio_cmn_power_well_ops, }, -- GitLab From efd814b73cfcf4ed1cb561561d8df6daccb3ceb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 Jun 2014 19:52:13 +0300 Subject: [PATCH 0089/5088] drm/i915: Polish the chv cmnlane resrt macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the semi-funky cmnlane assert/deassert macros with something a bit more conventional. Also protect the macro arguments properly (also for PHY_POWERGOOD()). Reviewed-by: Rafael Barbalho Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 7 ++----- drivers/gpu/drm/i915/intel_pm.c | 8 ++++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index fbdb08f4cd76..468ef09d698d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1697,12 +1697,9 @@ enum punit_power_well { #define DPIO_PHY_STATUS (VLV_DISPLAY_BASE + 0x6240) #define DPLL_PORTD_READY_MASK (0xf) #define DISPLAY_PHY_CONTROL (VLV_DISPLAY_BASE + 0x60100) -#define PHY_COM_LANE_RESET_DEASSERT(phy, val) \ - ((phy == DPIO_PHY0) ? (val | 1) : (val | 2)) -#define PHY_COM_LANE_RESET_ASSERT(phy, val) \ - ((phy == DPIO_PHY0) ? (val & ~1) : (val & ~2)) +#define PHY_COM_LANE_RESET_DEASSERT(phy) (1 << (phy)) #define DISPLAY_PHY_STATUS (VLV_DISPLAY_BASE + 0x60104) -#define PHY_POWERGOOD(phy) ((phy == DPIO_PHY0) ? (1<<31) : (1<<30)) +#define PHY_POWERGOOD(phy) (((phy) == DPIO_PHY0) ? (1<<31) : (1<<30)) /* * The i830 generation, in LVDS mode, defines P1 as the bit number set within diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index aaae22815965..42bb329b2d05 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6359,8 +6359,8 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & PHY_POWERGOOD(phy), 1)) DRM_ERROR("Display PHY %d is not power up\n", phy); - I915_WRITE(DISPLAY_PHY_CONTROL, - PHY_COM_LANE_RESET_DEASSERT(phy, I915_READ(DISPLAY_PHY_CONTROL))); + I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) | + PHY_COM_LANE_RESET_DEASSERT(phy)); } static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, @@ -6380,8 +6380,8 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, assert_pll_disabled(dev_priv, PIPE_C); } - I915_WRITE(DISPLAY_PHY_CONTROL, - PHY_COM_LANE_RESET_ASSERT(phy, I915_READ(DISPLAY_PHY_CONTROL))); + I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) & + ~PHY_COM_LANE_RESET_DEASSERT(phy)); vlv_set_power_well(dev_priv, power_well, false); } -- GitLab From 692ef70c016b5035ad1942ccc2bc4040aa290044 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 5 Aug 2014 07:51:18 -0700 Subject: [PATCH 0090/5088] drm/i915: clean up PPGTT checking logic sanitize_enable_ppgtt is the function that checks all the conditions, honoring a forced ppgtt status or doing auto-detect as necessary. Just make sure it returns the right value in all cases and use that in the macros instead of the confusing intel_enable_ppgtt() function. Signed-off-by: Jesse Barnes Signed-off-by: Rodrigo Vivi [danvet: Don't reenable full ppgtt through the backdoor.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 11 ----------- drivers/gpu/drm/i915/i915_gem_gtt.h | 1 - 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 73d2308e2377..125a83c70768 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2065,8 +2065,8 @@ struct drm_i915_cmd_table { #define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_PPGTT(dev) (INTEL_INFO(dev)->gen >= 7 && !IS_GEN8(dev)) -#define USES_PPGTT(dev) intel_enable_ppgtt(dev, false) -#define USES_FULL_PPGTT(dev) intel_enable_ppgtt(dev, true) +#define USES_PPGTT(dev) (i915.enable_ppgtt) +#define USES_FULL_PPGTT(dev) (i915.enable_ppgtt == 2) #define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) #define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 1411613f2174..b4b7cfd226b7 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -33,17 +33,6 @@ static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv); static void chv_setup_private_ppat(struct drm_i915_private *dev_priv); -bool intel_enable_ppgtt(struct drm_device *dev, bool full) -{ - if (i915.enable_ppgtt == 0) - return false; - - if (i915.enable_ppgtt == 1 && full) - return false; - - return true; -} - static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt) { if (enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev)) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 8d6f7c18c404..666c938a51e3 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -272,7 +272,6 @@ void i915_gem_init_global_gtt(struct drm_device *dev); void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, unsigned long mappable_end, unsigned long end); -bool intel_enable_ppgtt(struct drm_device *dev, bool full); int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); void i915_check_and_clear_faults(struct drm_device *dev); -- GitLab From e2fcdaa9c951c51d558fea2cc020d89b382d702e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Aug 2014 14:02:51 +0300 Subject: [PATCH 0091/5088] drm/i915: Free pending page flip events at .preclose() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there are pending page flips when the fd gets closed those page flips may have events associated to them. When the page flip eventually completes it will queue the event to file_priv->event_list, but that may be too late and file_priv->event_list has already been cleaned up. Thus we leak a bit of kernel memory in the form of the event structure. To avoid such problems clear out such pending events from intel_crtc->unpin_work at ->preclose(). Any event that already made it to file_priv->event_list will get cleaned up by the drm_release_events() a bit later. We can ignore the file_priv->event_space accounting since file_priv is going away. This is already how drm core deals with pending vblank events, which are maintained by the drm core. What saves us from a total disaster (ie. dereferencing and alrady freed file_priv) is the fact that the fb descruction triggers a modeset and there we wait for pending flips. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ drivers/gpu/drm/i915/intel_display.c | 22 ++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 26 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2e7f03ad5ee2..c965698a8bac 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1981,6 +1981,9 @@ void i915_driver_preclose(struct drm_device *dev, struct drm_file *file) i915_gem_context_close(dev, file); i915_gem_release(dev, file); mutex_unlock(&dev->struct_mutex); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + intel_modeset_preclose(dev, file); } void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f32a94544940..24295694e493 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13470,3 +13470,25 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m, err_printf(m, " VSYNC: %08x\n", error->transcoder[i].vsync); } } + +void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file) +{ + struct intel_crtc *crtc; + + for_each_intel_crtc(dev, crtc) { + struct intel_unpin_work *work; + unsigned long irqflags; + + spin_lock_irqsave(&dev->event_lock, irqflags); + + work = crtc->unpin_work; + + if (work && work->event && + work->event->base.file_priv == file) { + kfree(work->event); + work->event = NULL; + } + + spin_unlock_irqrestore(&dev->event_lock, irqflags); + } +} diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 79782094c8f9..666ca8a044ea 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -892,6 +892,7 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_config *pipe_config); int intel_format_to_fourcc(int format); void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); +void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); -- GitLab From 0948c2651413d56c90d7ee9c99d75bef82d4c351 Mon Sep 17 00:00:00 2001 From: Gajanan Bhat Date: Thu, 7 Aug 2014 01:58:24 +0530 Subject: [PATCH 0092/5088] drm/i915: Generalize drain latency computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modify drain latency computation to use it for any plane. Same function can be used for primary, cursor and sprite planes. v2: Adressed review comments by Imre and Ville. - Moved clock round up in separate patch - Added WARN check for clock and pixel size - Simplified bit masking - Use cursor_base instead of reg read v3: Changed to bitwise shorthand operator for plane_dl assignment. Signed-off-by: Gajanan Bhat Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 87 +++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 468ef09d698d..d0cff5630569 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4009,6 +4009,7 @@ enum punit_power_well { #define DDL_PLANE_PRECISION_64 (1<<7) #define DDL_PLANE_PRECISION_32 (0<<7) #define DDL_PLANE_SHIFT 0 +#define DRAIN_LATENCY_MASK 0x7f /* FIFO watermark sizes etc */ #define G4X_FIFO_LINE_SIZE 64 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 42bb329b2d05..de27439636e8 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1271,33 +1271,24 @@ static bool g4x_compute_srwm(struct drm_device *dev, display, cursor); } -static bool vlv_compute_drain_latency(struct drm_device *dev, - int plane, - int *plane_prec_mult, - int *plane_dl, - int *cursor_prec_mult, - int *cursor_dl) +static bool vlv_compute_drain_latency(struct drm_crtc *crtc, + int pixel_size, + int *prec_mult, + int *drain_latency) { - struct drm_crtc *crtc; - int clock, pixel_size; int entries; + int clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; - crtc = intel_get_crtc_for_plane(dev, plane); - if (!intel_crtc_active(crtc)) + if (WARN(clock == 0, "Pixel clock is zero!\n")) return false; - clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; - pixel_size = crtc->primary->fb->bits_per_pixel / 8; /* BPP */ + if (WARN(pixel_size == 0, "Pixel size is zero!\n")) + return false; entries = (clock / 1000) * pixel_size; - *plane_prec_mult = (entries > 128) ? - DRAIN_LATENCY_PRECISION_64 : DRAIN_LATENCY_PRECISION_32; - *plane_dl = (64 * (*plane_prec_mult) * 4) / entries; - - entries = (clock / 1000) * 4; /* BPP is always 4 for cursor */ - *cursor_prec_mult = (entries > 128) ? - DRAIN_LATENCY_PRECISION_64 : DRAIN_LATENCY_PRECISION_32; - *cursor_dl = (64 * (*cursor_prec_mult) * 4) / entries; + *prec_mult = (entries > 128) ? DRAIN_LATENCY_PRECISION_64 : + DRAIN_LATENCY_PRECISION_32; + *drain_latency = (64 * (*prec_mult) * 4) / entries; return true; } @@ -1312,24 +1303,46 @@ static bool vlv_compute_drain_latency(struct drm_device *dev, static void vlv_update_drain_latency(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe pipe = to_intel_crtc(crtc)->pipe; - int plane_prec, plane_dl; - int cursor_prec, cursor_dl; - int plane_prec_mult, cursor_prec_mult; - - if (vlv_compute_drain_latency(dev, pipe, &plane_prec_mult, &plane_dl, - &cursor_prec_mult, &cursor_dl)) { - cursor_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_64) ? - DDL_CURSOR_PRECISION_64 : DDL_CURSOR_PRECISION_32; - plane_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_64) ? - DDL_PLANE_PRECISION_64 : DDL_PLANE_PRECISION_32; - - I915_WRITE(VLV_DDL(pipe), cursor_prec | - (cursor_dl << DDL_CURSOR_SHIFT) | - plane_prec | (plane_dl << DDL_PLANE_SHIFT)); + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pixel_size; + int drain_latency; + enum pipe pipe = intel_crtc->pipe; + int plane_prec, prec_mult, plane_dl; + + plane_dl = I915_READ(VLV_DDL(pipe)) & ~(DDL_PLANE_PRECISION_64 | + DRAIN_LATENCY_MASK | DDL_CURSOR_PRECISION_64 | + (DRAIN_LATENCY_MASK << DDL_CURSOR_SHIFT)); + + if (!intel_crtc_active(crtc)) { + I915_WRITE(VLV_DDL(pipe), plane_dl); + return; + } + + /* Primary plane Drain Latency */ + pixel_size = crtc->primary->fb->bits_per_pixel / 8; /* BPP */ + if (vlv_compute_drain_latency(crtc, pixel_size, &prec_mult, &drain_latency)) { + plane_prec = (prec_mult == DRAIN_LATENCY_PRECISION_64) ? + DDL_PLANE_PRECISION_64 : + DDL_PLANE_PRECISION_32; + plane_dl |= plane_prec | drain_latency; } + + /* Cursor Drain Latency + * BPP is always 4 for cursor + */ + pixel_size = 4; + + /* Program cursor DL only if it is enabled */ + if (intel_crtc->cursor_base && + vlv_compute_drain_latency(crtc, pixel_size, &prec_mult, &drain_latency)) { + plane_prec = (prec_mult == DRAIN_LATENCY_PRECISION_64) ? + DDL_CURSOR_PRECISION_64 : + DDL_CURSOR_PRECISION_32; + plane_dl |= plane_prec | (drain_latency << DDL_CURSOR_SHIFT); + } + + I915_WRITE(VLV_DDL(pipe), plane_dl); } #define single_plane_enabled(mask) is_power_of_2(mask) -- GitLab From a398e9c79eea74ba2f3f24ac08902661682f008c Mon Sep 17 00:00:00 2001 From: Gajanan Bhat Date: Tue, 5 Aug 2014 23:15:54 +0530 Subject: [PATCH 0093/5088] drm/i915: Round-up clock and limit drain latency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Round up clock computation and limit drain latency to maximum of 0x7F. Signed-off-by: Gajanan Bhat Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index de27439636e8..19bd7212f4a2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1285,11 +1285,14 @@ static bool vlv_compute_drain_latency(struct drm_crtc *crtc, if (WARN(pixel_size == 0, "Pixel size is zero!\n")) return false; - entries = (clock / 1000) * pixel_size; + entries = DIV_ROUND_UP(clock, 1000) * pixel_size; *prec_mult = (entries > 128) ? DRAIN_LATENCY_PRECISION_64 : DRAIN_LATENCY_PRECISION_32; *drain_latency = (64 * (*prec_mult) * 4) / entries; + if (*drain_latency > DRAIN_LATENCY_MASK) + *drain_latency = DRAIN_LATENCY_MASK; + return true; } -- GitLab From 01e184cc85d4516cab0ecea7c2c43a2dd3ad432b Mon Sep 17 00:00:00 2001 From: Gajanan Bhat Date: Thu, 7 Aug 2014 17:03:30 +0530 Subject: [PATCH 0094/5088] drm/i915: Add sprite watermark programming for VLV and CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Program DDL register as part of sprite watermark programming for CHV and VLV. v2: Rename DRAIN_LATENCY_MAX by DRAIN_LATENCY_MASK v3: Addressed review comments by Ville - Changed Sprite DDL definitions to more generic to avoid multiple if-else - Changed bit masking to customary form - Changed to bitwise shorthand operator for sprite_dl assignment Signed-off-by: Gajanan Bhat Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 9 +++------ drivers/gpu/drm/i915/intel_pm.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d0cff5630569..7a6cc69cdc2b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4000,12 +4000,9 @@ enum punit_power_well { #define DDL_CURSOR_PRECISION_64 (1<<31) #define DDL_CURSOR_PRECISION_32 (0<<31) #define DDL_CURSOR_SHIFT 24 -#define DDL_SPRITE1_PRECISION_64 (1<<23) -#define DDL_SPRITE1_PRECISION_32 (0<<23) -#define DDL_SPRITE1_SHIFT 16 -#define DDL_SPRITE0_PRECISION_64 (1<<15) -#define DDL_SPRITE0_PRECISION_32 (0<<15) -#define DDL_SPRITE0_SHIFT 8 +#define DDL_SPRITE_PRECISION_64(sprite) (1<<(15+8*(sprite))) +#define DDL_SPRITE_PRECISION_32(sprite) (0<<(15+8*(sprite))) +#define DDL_SPRITE_SHIFT(sprite) (8+8*(sprite)) #define DDL_PLANE_PRECISION_64 (1<<7) #define DDL_PLANE_PRECISION_32 (0<<7) #define DDL_PLANE_SHIFT 0 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 19bd7212f4a2..41de760bf1d4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1494,6 +1494,37 @@ static void cherryview_update_wm(struct drm_crtc *crtc) intel_set_memory_cxsr(dev_priv, true); } +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; + int pipe = to_intel_plane(plane)->pipe; + int sprite = to_intel_plane(plane)->plane; + int drain_latency; + int plane_prec; + int sprite_dl; + int prec_mult; + + sprite_dl = I915_READ(VLV_DDL(pipe)) & ~(DDL_SPRITE_PRECISION_64(sprite) | + (DRAIN_LATENCY_MASK << DDL_SPRITE_SHIFT(sprite))); + + if (enabled && vlv_compute_drain_latency(crtc, pixel_size, &prec_mult, + &drain_latency)) { + plane_prec = (prec_mult == DRAIN_LATENCY_PRECISION_64) ? + DDL_SPRITE_PRECISION_64(sprite) : + DDL_SPRITE_PRECISION_32(sprite); + sprite_dl |= plane_prec | + (drain_latency << DDL_SPRITE_SHIFT(sprite)); + } + + I915_WRITE(VLV_DDL(pipe), sprite_dl); +} + static void g4x_update_wm(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -7225,10 +7256,12 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.init_clock_gating = gen8_init_clock_gating; } else if (IS_CHERRYVIEW(dev)) { dev_priv->display.update_wm = cherryview_update_wm; + dev_priv->display.update_sprite_wm = valleyview_update_sprite_wm; 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; dev_priv->display.init_clock_gating = valleyview_init_clock_gating; } else if (IS_PINEVIEW(dev)) { -- GitLab From 403bdd10c815029694046adf5ffde0577cbd2866 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 7 Aug 2014 16:05:39 +0200 Subject: [PATCH 0095/5088] drm/i915: No busy-loop wait_for in the ring init code Doing a 1s wait (tops) with the cpu is a bit excessive. Tune it down like everything else in that code. v2: Also insert the missing space Chris spotted. Cc: Naresh Kumar Kachhi Cc: Chris Wilson Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 16371a444426..117543e58d48 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -476,8 +476,8 @@ static bool stop_ring(struct intel_engine_cs *ring) if (!IS_GEN2(ring->dev)) { I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING)); - if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) { - DRM_ERROR("%s :timed out trying to stop ring\n", ring->name); + if (wait_for((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) { + DRM_ERROR("%s : timed out trying to stop ring\n", ring->name); return false; } } -- GitLab From 10f637bf292ba501f9b9e9df6dfe21d8fa521fbd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 29 Jul 2014 13:47:11 +0200 Subject: [PATCH 0096/5088] drm: Add drm_plane/connector_index In the atomic state we'll have an array of states for crtcs, planes and connectors and need to be able to at them by their index. We already have a drm_crtc_index function so add the missing ones for planes and connectors. If it later on turns out that the list walking is too expensive we can add the index to the relevant modeset objects. Rob Clark doesn't like the loops too much, but we can always add an obj->idx parameter later on. And for now reiterating is actually safer since nowadays we have hotpluggable connectors (thanks to DP MST). v2: Fix embarrassing copypasta fail in kerneldoc and header declarations, spotted by Matt Roper. Cc: Matt Roper Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 46 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 66d3bfb8d264..f3ef461deeb8 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1021,6 +1021,29 @@ void drm_connector_cleanup(struct drm_connector *connector) } EXPORT_SYMBOL(drm_connector_cleanup); +/** + * drm_connector_index - find the index of a registered connector + * @connector: connector to find index for + * + * Given a registered connector, return the index of that connector within a DRM + * device's list of connectors. + */ +unsigned int drm_connector_index(struct drm_connector *connector) +{ + unsigned int index = 0; + struct drm_connector *tmp; + + list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { + if (tmp == connector) + return index; + + index++; + } + + BUG(); +} +EXPORT_SYMBOL(drm_connector_index); + /** * drm_connector_register - register a connector * @connector: the connector to register @@ -1325,6 +1348,29 @@ void drm_plane_cleanup(struct drm_plane *plane) } EXPORT_SYMBOL(drm_plane_cleanup); +/** + * drm_plane_index - find the index of a registered plane + * @plane: plane to find index for + * + * Given a registered plane, return the index of that CRTC within a DRM + * device's list of planes. + */ +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) { + if (tmp == plane) + return index; + + index++; + } + + BUG(); +} +EXPORT_SYMBOL(drm_plane_index); + /** * drm_plane_force_disable - Forcibly disable a plane * @plane: plane to disable diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c530b4920a09..9f18e7022ab3 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -904,6 +904,7 @@ int drm_connector_register(struct drm_connector *connector); void drm_connector_unregister(struct drm_connector *connector); extern void drm_connector_cleanup(struct drm_connector *connector); +extern unsigned int drm_connector_index(struct drm_connector *connector); /* helper to unplug all connectors from sysfs for device */ extern void drm_connector_unplug_all(struct drm_device *dev); @@ -943,6 +944,7 @@ extern int drm_plane_init(struct drm_device *dev, const uint32_t *formats, uint32_t format_count, bool is_primary); extern void drm_plane_cleanup(struct drm_plane *plane); +extern unsigned int drm_plane_index(struct drm_plane *plane); extern void drm_plane_force_disable(struct drm_plane *plane); extern int drm_crtc_check_viewport(const struct drm_crtc *crtc, int x, int y, -- GitLab From a6a8bb848d5ca40bc0eb708ddeb23df2b0eca1fb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 25 Jul 2014 17:47:18 +0200 Subject: [PATCH 0097/5088] drm: Move modeset_lock_all helpers to drm_modeset_lock.[hc] Somehow we've forgotten about this little bit of OCD. Reviewed-by: Dave Airlie Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 95 ------------------------------ drivers/gpu/drm/drm_modeset_lock.c | 95 ++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 4 -- include/drm/drm_modeset_lock.h | 5 ++ 4 files changed, 100 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f3ef461deeb8..caaa01f3b353 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -45,101 +45,6 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, struct drm_mode_fb_cmd2 *r, struct drm_file *file_priv); -/** - * drm_modeset_lock_all - take all modeset locks - * @dev: drm device - * - * This function takes all modeset locks, suitable where a more fine-grained - * scheme isn't (yet) implemented. Locks must be dropped with - * drm_modeset_unlock_all. - */ -void drm_modeset_lock_all(struct drm_device *dev) -{ - struct drm_mode_config *config = &dev->mode_config; - struct drm_modeset_acquire_ctx *ctx; - int ret; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (WARN_ON(!ctx)) - return; - - mutex_lock(&config->mutex); - - drm_modeset_acquire_init(ctx, 0); - -retry: - ret = drm_modeset_lock(&config->connection_mutex, ctx); - if (ret) - goto fail; - ret = drm_modeset_lock_all_crtcs(dev, ctx); - if (ret) - goto fail; - - WARN_ON(config->acquire_ctx); - - /* now we hold the locks, so now that it is safe, stash the - * ctx for drm_modeset_unlock_all(): - */ - config->acquire_ctx = ctx; - - drm_warn_on_modeset_not_all_locked(dev); - - return; - -fail: - if (ret == -EDEADLK) { - drm_modeset_backoff(ctx); - goto retry; - } -} -EXPORT_SYMBOL(drm_modeset_lock_all); - -/** - * drm_modeset_unlock_all - drop all modeset locks - * @dev: device - * - * This function drop all modeset locks taken by drm_modeset_lock_all. - */ -void drm_modeset_unlock_all(struct drm_device *dev) -{ - struct drm_mode_config *config = &dev->mode_config; - struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; - - if (WARN_ON(!ctx)) - return; - - config->acquire_ctx = NULL; - drm_modeset_drop_locks(ctx); - drm_modeset_acquire_fini(ctx); - - kfree(ctx); - - mutex_unlock(&dev->mode_config.mutex); -} -EXPORT_SYMBOL(drm_modeset_unlock_all); - -/** - * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked - * @dev: device - * - * Useful as a debug assert. - */ -void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) -{ - struct drm_crtc *crtc; - - /* Locking is currently fubar in the panic handler. */ - if (oops_in_progress) - return; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); - - WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); - WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); -} -EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); - /* Avoid boilerplate. I'm tired of typing. */ #define DRM_ENUM_NAME_FN(fnname, list) \ const char *fnname(int val) \ diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 0dc57d5ecd10..73e6534fd0aa 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -56,6 +56,101 @@ */ +/** + * drm_modeset_lock_all - take all modeset locks + * @dev: drm device + * + * This function takes all modeset locks, suitable where a more fine-grained + * scheme isn't (yet) implemented. Locks must be dropped with + * drm_modeset_unlock_all. + */ +void drm_modeset_lock_all(struct drm_device *dev) +{ + struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx *ctx; + int ret; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (WARN_ON(!ctx)) + return; + + mutex_lock(&config->mutex); + + drm_modeset_acquire_init(ctx, 0); + +retry: + ret = drm_modeset_lock(&config->connection_mutex, ctx); + if (ret) + goto fail; + ret = drm_modeset_lock_all_crtcs(dev, ctx); + if (ret) + goto fail; + + WARN_ON(config->acquire_ctx); + + /* now we hold the locks, so now that it is safe, stash the + * ctx for drm_modeset_unlock_all(): + */ + config->acquire_ctx = ctx; + + drm_warn_on_modeset_not_all_locked(dev); + + return; + +fail: + if (ret == -EDEADLK) { + drm_modeset_backoff(ctx); + goto retry; + } +} +EXPORT_SYMBOL(drm_modeset_lock_all); + +/** + * drm_modeset_unlock_all - drop all modeset locks + * @dev: device + * + * This function drop all modeset locks taken by drm_modeset_lock_all. + */ +void drm_modeset_unlock_all(struct drm_device *dev) +{ + struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; + + if (WARN_ON(!ctx)) + return; + + config->acquire_ctx = NULL; + drm_modeset_drop_locks(ctx); + drm_modeset_acquire_fini(ctx); + + kfree(ctx); + + mutex_unlock(&dev->mode_config.mutex); +} +EXPORT_SYMBOL(drm_modeset_unlock_all); + +/** + * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked + * @dev: device + * + * Useful as a debug assert. + */ +void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) +{ + struct drm_crtc *crtc; + + /* Locking is currently fubar in the panic handler. */ + if (oops_in_progress) + return; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); + + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); +} +EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); + /** * drm_modeset_acquire_init - initialize acquire context * @ctx: the acquire context diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 9f18e7022ab3..a11d73422e7f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -218,10 +218,6 @@ struct drm_property { struct list_head enum_blob_list; }; -void drm_modeset_lock_all(struct drm_device *dev); -void drm_modeset_unlock_all(struct drm_device *dev); -void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); - struct drm_crtc; struct drm_connector; struct drm_encoder; diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index 402aa7a6a058..cf61e857bc06 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -120,6 +120,11 @@ int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, void drm_modeset_unlock(struct drm_modeset_lock *lock); struct drm_device; + +void drm_modeset_lock_all(struct drm_device *dev); +void drm_modeset_unlock_all(struct drm_device *dev); +void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); + int drm_modeset_lock_all_crtcs(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); -- GitLab From d059f652e73c35678d28d4cd09ab2cec89696af9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 25 Jul 2014 18:07:40 +0200 Subject: [PATCH 0098/5088] drm: Handle legacy per-crtc locking with full acquire ctx So drivers using the atomic interfaces expect that they can acquire additional locks internal to the driver as-needed. Examples would be locks to protect shared state like shared display PLLs. Unfortunately the legacy ioctls assume that all locking is fully done by the drm core. Now for those paths which grab all locks we already have to keep around an acquire context in dev->mode_config. Helper functions that implement legacy interfaces in terms of atomic support can therefore grab this acquire contexts and reuse it. The only interfaces left are the cursor and pageflip ioctls. So add functions to grab the crtc lock these need using an acquire context and preserve it for atomic drivers to reuse. v2: - Fixup comments&kerneldoc. - Drop the WARNING from modeset_lock_all_crtcs since that can be used in legacy paths with crtc locking. v3: Fix a type on the kerneldoc Dave spotted. Cc: Dave Airlie Reviewed-by: Dave Airlie Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 8 +-- drivers/gpu/drm/drm_modeset_lock.c | 84 ++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 6 +++ include/drm/drm_modeset_lock.h | 5 ++ 4 files changed, 99 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index caaa01f3b353..ab121b6d980c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2801,7 +2801,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, if (crtc->cursor) return drm_mode_cursor_universal(crtc, req, file_priv); - drm_modeset_lock(&crtc->mutex, NULL); + drm_modeset_lock_crtc(crtc); if (req->flags & DRM_MODE_CURSOR_BO) { if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { ret = -ENXIO; @@ -2825,7 +2825,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, } } out: - drm_modeset_unlock(&crtc->mutex); + drm_modeset_unlock_crtc(crtc); return ret; @@ -4561,7 +4561,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, if (!crtc) return -ENOENT; - drm_modeset_lock(&crtc->mutex, NULL); + drm_modeset_lock_crtc(crtc); if (crtc->primary->fb == NULL) { /* The framebuffer is currently unbound, presumably * due to a hotplug event, that userspace has not @@ -4645,7 +4645,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, drm_framebuffer_unreference(fb); if (old_fb) drm_framebuffer_unreference(old_fb); - drm_modeset_unlock(&crtc->mutex); + drm_modeset_unlock_crtc(crtc); return ret; } diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 73e6534fd0aa..4753c8bd5ab5 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -129,6 +129,90 @@ void drm_modeset_unlock_all(struct drm_device *dev) } EXPORT_SYMBOL(drm_modeset_unlock_all); +/** + * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx + * @crtc: drm crtc + * + * This function locks the given crtc using a hidden acquire context. This is + * necessary so that drivers internally using the atomic interfaces can grab + * further locks with the lock acquire context. + */ +void drm_modeset_lock_crtc(struct drm_crtc *crtc) +{ + struct drm_modeset_acquire_ctx *ctx; + int ret; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (WARN_ON(!ctx)) + return; + + drm_modeset_acquire_init(ctx, 0); + +retry: + ret = drm_modeset_lock(&crtc->mutex, ctx); + if (ret) + goto fail; + + WARN_ON(crtc->acquire_ctx); + + /* now we hold the locks, so now that it is safe, stash the + * ctx for drm_modeset_unlock_crtc(): + */ + crtc->acquire_ctx = ctx; + + return; + +fail: + if (ret == -EDEADLK) { + drm_modeset_backoff(ctx); + goto retry; + } +} +EXPORT_SYMBOL(drm_modeset_lock_crtc); + +/** + * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls + * crtc: drm crtc + * + * Legacy ioctl operations like cursor updates or page flips only have per-crtc + * locking, and store the acquire ctx in the corresponding crtc. All other + * legacy operations take all locks and use a global acquire context. This + * function grabs the right one. + */ +struct drm_modeset_acquire_ctx * +drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc) +{ + if (crtc->acquire_ctx) + return crtc->acquire_ctx; + + WARN_ON(!crtc->dev->mode_config.acquire_ctx); + + return crtc->dev->mode_config.acquire_ctx; +} +EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx); + +/** + * drm_modeset_unlock_crtc - drop crtc lock + * @crtc: drm crtc + * + * This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other + * locks acquired through the hidden context. + */ +void drm_modeset_unlock_crtc(struct drm_crtc *crtc) +{ + struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx; + + if (WARN_ON(!ctx)) + return; + + crtc->acquire_ctx = NULL; + drm_modeset_drop_locks(ctx); + drm_modeset_acquire_fini(ctx); + + kfree(ctx); +} +EXPORT_SYMBOL(drm_modeset_unlock_crtc); + /** * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked * @dev: device diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index a11d73422e7f..508817bae538 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -371,6 +371,12 @@ struct drm_crtc { void *helper_private; struct drm_object_properties properties; + + /* + * For legacy crtc ioctls so that atomic drivers can get at the locking + * acquire context. + */ + struct drm_modeset_acquire_ctx *acquire_ctx; }; diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index cf61e857bc06..d38e1508f11a 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -120,10 +120,15 @@ int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, void drm_modeset_unlock(struct drm_modeset_lock *lock); struct drm_device; +struct drm_crtc; void drm_modeset_lock_all(struct drm_device *dev); void drm_modeset_unlock_all(struct drm_device *dev); +void drm_modeset_lock_crtc(struct drm_crtc *crtc); +void drm_modeset_unlock_crtc(struct drm_crtc *crtc); void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); +struct drm_modeset_acquire_ctx * +drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc); int drm_modeset_lock_all_crtcs(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); -- GitLab From 3d30a59bfcb7c96d4aacdb053c2ccc49394b2311 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 27 Jul 2014 13:42:42 +0200 Subject: [PATCH 0099/5088] drm: Move ->old_fb from crtc to plane Atomic implemenations for legacy ioctls must be able to drop locks. Which doesn't cause havoc since we only do that while constructing the new state, so no driver or hardware state change has happened. The only troubling bit is the fb refcounting the core does - if someone else has snuck in then it might potentially unref an outdated framebuffer. To fix that move the old_fb temporary storage into struct drm_plane for all ioctls, so that the atomic helpers can update it. v2: Fix up the error case handling as suggested by Matt Roper and just grab locks uncoditionally - there's no point in optimizing the locking for when userspace gets it wrong. Cc: Matt Roper Cc: Dave Airlie Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 46 ++++++++++++++++++++------------------ include/drm/drm_crtc.h | 8 +++---- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index ab121b6d980c..cacb460a7145 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1287,19 +1287,21 @@ EXPORT_SYMBOL(drm_plane_index); */ void drm_plane_force_disable(struct drm_plane *plane) { - struct drm_framebuffer *old_fb = plane->fb; int ret; - if (!old_fb) + if (!plane->fb) return; + plane->old_fb = plane->fb; ret = plane->funcs->disable_plane(plane); if (ret) { DRM_ERROR("failed to disable plane with busy fb\n"); + plane->old_fb = NULL; return; } /* disconnect the plane from the fb and crtc: */ - __drm_framebuffer_unreference(old_fb); + __drm_framebuffer_unreference(plane->old_fb); + plane->old_fb = NULL; plane->fb = NULL; plane->crtc = NULL; } @@ -2275,23 +2277,21 @@ static int setplane_internal(struct drm_plane *plane, uint32_t src_w, uint32_t src_h) { struct drm_device *dev = plane->dev; - struct drm_framebuffer *old_fb = NULL; int ret = 0; unsigned int fb_width, fb_height; int i; + drm_modeset_lock_all(dev); /* No fb means shut it down */ if (!fb) { - drm_modeset_lock_all(dev); - old_fb = plane->fb; + plane->old_fb = plane->fb; ret = plane->funcs->disable_plane(plane); if (!ret) { plane->crtc = NULL; plane->fb = NULL; } else { - old_fb = NULL; + plane->old_fb = NULL; } - drm_modeset_unlock_all(dev); goto out; } @@ -2331,8 +2331,7 @@ static int setplane_internal(struct drm_plane *plane, goto out; } - drm_modeset_lock_all(dev); - old_fb = plane->fb; + plane->old_fb = plane->fb; ret = plane->funcs->update_plane(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h); @@ -2341,15 +2340,16 @@ static int setplane_internal(struct drm_plane *plane, plane->fb = fb; fb = NULL; } else { - old_fb = NULL; + plane->old_fb = NULL; } - drm_modeset_unlock_all(dev); out: if (fb) drm_framebuffer_unreference(fb); - if (old_fb) - drm_framebuffer_unreference(old_fb); + if (plane->old_fb) + drm_framebuffer_unreference(plane->old_fb); + plane->old_fb = NULL; + drm_modeset_unlock_all(dev); return ret; @@ -2456,7 +2456,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) * crtcs. Atomic modeset will have saner semantics ... */ list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) - tmp->old_fb = tmp->primary->fb; + tmp->primary->old_fb = tmp->primary->fb; fb = set->fb; @@ -2469,8 +2469,9 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { if (tmp->primary->fb) drm_framebuffer_reference(tmp->primary->fb); - if (tmp->old_fb) - drm_framebuffer_unreference(tmp->old_fb); + if (tmp->primary->old_fb) + drm_framebuffer_unreference(tmp->primary->old_fb); + tmp->primary->old_fb = NULL; } return ret; @@ -4545,7 +4546,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, { struct drm_mode_crtc_page_flip *page_flip = data; struct drm_crtc *crtc; - struct drm_framebuffer *fb = NULL, *old_fb = NULL; + struct drm_framebuffer *fb = NULL; struct drm_pending_vblank_event *e = NULL; unsigned long flags; int ret = -EINVAL; @@ -4617,7 +4618,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, (void (*) (struct drm_pending_event *)) kfree; } - old_fb = crtc->primary->fb; + crtc->primary->old_fb = crtc->primary->fb; ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); if (ret) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { @@ -4627,7 +4628,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, kfree(e); } /* Keep the old fb, don't unref it. */ - old_fb = NULL; + crtc->primary->old_fb = NULL; } else { /* * Warn if the driver hasn't properly updated the crtc->fb @@ -4643,8 +4644,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, out: if (fb) drm_framebuffer_unreference(fb); - if (old_fb) - drm_framebuffer_unreference(old_fb); + if (crtc->primary->old_fb) + drm_framebuffer_unreference(crtc->primary->old_fb); + crtc->primary->old_fb = NULL; drm_modeset_unlock_crtc(crtc); return ret; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 508817bae538..279565aa0c33 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -341,10 +341,6 @@ struct drm_crtc { int cursor_x; int cursor_y; - /* Temporary tracking of the old fb while a modeset is ongoing. Used - * by drm_mode_set_config_internal to implement correct refcounting. */ - struct drm_framebuffer *old_fb; - bool enabled; /* Requested mode from modesetting. */ @@ -623,6 +619,10 @@ struct drm_plane { struct drm_crtc *crtc; struct drm_framebuffer *fb; + /* Temporary tracking of the old fb while a modeset is ongoing. Used + * by drm_mode_set_config_internal to implement correct refcounting. */ + struct drm_framebuffer *old_fb; + const struct drm_plane_funcs *funcs; struct drm_object_properties properties; -- GitLab From cb597bb3a2fbfc871cc1c703fb330d247bd21394 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 27 Jul 2014 19:09:33 +0200 Subject: [PATCH 0100/5088] drm: trylock modest locking for fbdev panics In the fbdev code we want to do trylocks only to avoid deadlocks and other ugly issues. Thus far we've only grabbed the overall modeset lock, but that already failed to exclude a pile of potential concurrent operations. With proper atomic support this will be worse. So add a trylock mode to the modeset locking code which attempts all locks only with trylocks, if possible. We need to track this in the locking functions themselves and can't restrict this to drivers since driver-private w/w mutexes must be treated the same way. There's still the issue that other driver private locks aren't handled here at all, but well can't have everything. With this we will at least not regress, even once atomic allows lots of concurrent kms activity. Aside: We should move the acquire context to stack-based allocation in the callers to get rid of that awful WARN_ON(kmalloc_failed) control flow which just blows up when memory is short. But that's material for separate patches. v2: - Fix logic inversion fumble in the fb helper. - Add proper kerneldoc. Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 10 +++--- drivers/gpu/drm/drm_modeset_lock.c | 56 +++++++++++++++++++++++------- include/drm/drm_modeset_lock.h | 6 ++++ 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3a6b6635e3f5..7b7b9565188f 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -365,11 +365,11 @@ static bool drm_fb_helper_force_kernel_mode(void) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) continue; - /* NOTE: we use lockless flag below to avoid grabbing other - * modeset locks. So just trylock the underlying mutex - * directly: + /* + * NOTE: Use trylock mode to avoid deadlocks and sleeping in + * panic context. */ - if (!mutex_trylock(&dev->mode_config.mutex)) { + if (__drm_modeset_lock_all(dev, true) != 0) { error = true; continue; } @@ -378,7 +378,7 @@ static bool drm_fb_helper_force_kernel_mode(void) if (ret) error = true; - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); } return error; } diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 4753c8bd5ab5..5280b64a0230 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -57,26 +57,37 @@ /** - * drm_modeset_lock_all - take all modeset locks - * @dev: drm device + * __drm_modeset_lock_all - internal helper to grab all modeset locks + * @dev: DRM device + * @trylock: trylock mode for atomic contexts * - * This function takes all modeset locks, suitable where a more fine-grained - * scheme isn't (yet) implemented. Locks must be dropped with - * drm_modeset_unlock_all. + * This is a special version of drm_modeset_lock_all() which can also be used in + * atomic contexts. Then @trylock must be set to true. + * + * Returns: + * 0 on success or negative error code on failure. */ -void drm_modeset_lock_all(struct drm_device *dev) +int __drm_modeset_lock_all(struct drm_device *dev, + bool trylock) { struct drm_mode_config *config = &dev->mode_config; struct drm_modeset_acquire_ctx *ctx; int ret; - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (WARN_ON(!ctx)) - return; + ctx = kzalloc(sizeof(*ctx), + trylock ? GFP_ATOMIC : GFP_KERNEL); + if (!ctx) + return -ENOMEM; - mutex_lock(&config->mutex); + if (trylock) { + if (!mutex_trylock(&config->mutex)) + return -EBUSY; + } else { + mutex_lock(&config->mutex); + } drm_modeset_acquire_init(ctx, 0); + ctx->trylock_only = trylock; retry: ret = drm_modeset_lock(&config->connection_mutex, ctx); @@ -95,13 +106,29 @@ void drm_modeset_lock_all(struct drm_device *dev) drm_warn_on_modeset_not_all_locked(dev); - return; + return 0; fail: if (ret == -EDEADLK) { drm_modeset_backoff(ctx); goto retry; } + + return ret; +} +EXPORT_SYMBOL(__drm_modeset_lock_all); + +/** + * drm_modeset_lock_all - take all modeset locks + * @dev: drm device + * + * This function takes all modeset locks, suitable where a more fine-grained + * scheme isn't (yet) implemented. Locks must be dropped with + * drm_modeset_unlock_all. + */ +void drm_modeset_lock_all(struct drm_device *dev) +{ + WARN_ON(__drm_modeset_lock_all(dev, false) != 0); } EXPORT_SYMBOL(drm_modeset_lock_all); @@ -287,7 +314,12 @@ static inline int modeset_lock(struct drm_modeset_lock *lock, WARN_ON(ctx->contended); - if (interruptible && slow) { + if (ctx->trylock_only) { + if (!ww_mutex_trylock(&lock->mutex)) + return -EBUSY; + else + return 0; + } else if (interruptible && slow) { ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); } else if (interruptible) { ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx); diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index d38e1508f11a..a3f736d24382 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -53,6 +53,11 @@ struct drm_modeset_acquire_ctx { * list of held locks (drm_modeset_lock) */ struct list_head locked; + + /** + * Trylock mode, use only for panic handlers! + */ + bool trylock_only; }; /** @@ -123,6 +128,7 @@ struct drm_device; struct drm_crtc; void drm_modeset_lock_all(struct drm_device *dev); +int __drm_modeset_lock_all(struct drm_device *dev, bool trylock); void drm_modeset_unlock_all(struct drm_device *dev); void drm_modeset_lock_crtc(struct drm_crtc *crtc); void drm_modeset_unlock_crtc(struct drm_crtc *crtc); -- GitLab From 2c0827cffca8ac0c654b888c58a1989a5172f007 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 8 Aug 2014 20:44:59 +0200 Subject: [PATCH 0101/5088] drm/i915: Update DRIVER_DATE to 20140808 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 125a83c70768..fab97bc3215f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -53,7 +53,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20140725" +#define DRIVER_DATE "20140808" enum pipe { INVALID_PIPE = -1, -- GitLab From 4fa790421c10e5c9c62406655c06d97a94555d54 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 8 Aug 2014 19:25:57 +0100 Subject: [PATCH 0102/5088] drm/i915: Fix erroneous conversion to u8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit adj was defined as u8. The issue is last_adj can be negative and adj is initialized with: adj = dev_priv->rps.last_adj; and we were also happily doing things like: if (adj < 0) (thank static analysers!) v2: Make new_delay an int in case we overflow the u8 in the intermediate computations. new_delay will get clamped at the end anyway. (Ville) Cc: Deepak S Cc: Ville Syrjälä Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 87abe8679495..f0d24db76e72 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1327,10 +1327,10 @@ static u32 vlv_c0_residency(struct drm_i915_private *dev_priv, * @dev_priv: DRM device private * */ -static u32 vlv_calc_delay_from_C0_counters(struct drm_i915_private *dev_priv) +static int vlv_calc_delay_from_C0_counters(struct drm_i915_private *dev_priv) { u32 residency_C0_up = 0, residency_C0_down = 0; - u8 new_delay, adj; + int new_delay, adj; dev_priv->rps.ei_interrupt_count++; -- GitLab From f45651bae2ee73ae551699d481f76aa6ad92138f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 8 Aug 2014 21:51:10 +0300 Subject: [PATCH 0103/5088] drm/i915: Eliminate rmw from .update_primary_plane() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the entire DSPCNTR register setup into the .update_primary_plane() functions. That's where it belongs anyway and it'll also help 830M which has the extra problem that plane registers reads will return the value latched at the last vblank, not the value that was last written. Also move DSPPOS and DSPSIZE setup there. v2: Don't move variable initialization to avoid churn later Reviewed-by: Matt Roper Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 100 +++++++++------------------ 1 file changed, 32 insertions(+), 68 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 24295694e493..041fd76a2ded 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2388,12 +2388,26 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, int plane = intel_crtc->plane; unsigned long linear_offset; u32 dspcntr; - u32 reg; + u32 reg = DSPCNTR(plane); + + dspcntr = DISPPLANE_GAMMA_ENABLE; + + if (intel_crtc->primary_enabled) + dspcntr |= DISPLAY_PLANE_ENABLE; + + if (INTEL_INFO(dev)->gen < 4) { + if (intel_crtc->pipe == PIPE_B) + dspcntr |= DISPPLANE_SEL_PIPE_B; + + /* pipesrc and dspsize control the size that is scaled from, + * which should always be the user's requested size. + */ + I915_WRITE(DSPSIZE(plane), + ((intel_crtc->config.pipe_src_h - 1) << 16) | + (intel_crtc->config.pipe_src_w - 1)); + I915_WRITE(DSPPOS(plane), 0); + } - reg = DSPCNTR(plane); - dspcntr = I915_READ(reg); - /* Mask out pixel format bits in case we change it */ - dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; switch (fb->pixel_format) { case DRM_FORMAT_C8: dspcntr |= DISPPLANE_8BPP; @@ -2425,12 +2439,9 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, BUG(); } - if (INTEL_INFO(dev)->gen >= 4) { - if (obj->tiling_mode != I915_TILING_NONE) - dspcntr |= DISPPLANE_TILED; - else - dspcntr &= ~DISPPLANE_TILED; - } + if (INTEL_INFO(dev)->gen >= 4 && + obj->tiling_mode != I915_TILING_NONE) + dspcntr |= DISPPLANE_TILED; if (IS_G4X(dev)) dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; @@ -2474,12 +2485,16 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, int plane = intel_crtc->plane; unsigned long linear_offset; u32 dspcntr; - u32 reg; + u32 reg = DSPCNTR(plane); + + dspcntr = DISPPLANE_GAMMA_ENABLE; + + if (intel_crtc->primary_enabled) + dspcntr |= DISPLAY_PLANE_ENABLE; + + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + dspcntr |= DISPPLANE_PIPE_CSC_ENABLE; - reg = DSPCNTR(plane); - dspcntr = I915_READ(reg); - /* Mask out pixel format bits in case we change it */ - dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; switch (fb->pixel_format) { case DRM_FORMAT_C8: dspcntr |= DISPPLANE_8BPP; @@ -2509,12 +2524,8 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, if (obj->tiling_mode != I915_TILING_NONE) dspcntr |= DISPPLANE_TILED; - else - dspcntr &= ~DISPPLANE_TILED; - if (IS_HASWELL(dev) || IS_BROADWELL(dev)) - dspcntr &= ~DISPPLANE_TRICKLE_FEED_DISABLE; - else + if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; I915_WRITE(reg, dspcntr); @@ -3936,7 +3947,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - enum plane plane = intel_crtc->plane; WARN_ON(!crtc->enabled); @@ -3958,10 +3968,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) ironlake_set_pipeconf(crtc); - /* Set up the display plane register */ - I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); - POSTING_READ(DSPCNTR(plane)); - dev_priv->display.update_primary_plane(crtc, crtc->primary->fb, crtc->x, crtc->y); @@ -4049,7 +4055,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - enum plane plane = intel_crtc->plane; WARN_ON(!crtc->enabled); @@ -4073,10 +4078,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_set_pipe_csc(crtc); - /* Set up the display plane register */ - I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE); - POSTING_READ(DSPCNTR(plane)); - dev_priv->display.update_primary_plane(crtc, crtc->primary->fb, crtc->x, crtc->y); @@ -4632,9 +4633,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; bool is_dsi; - u32 dspcntr; WARN_ON(!crtc->enabled); @@ -4650,27 +4649,13 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) vlv_prepare_pll(intel_crtc); } - /* Set up the display plane register */ - dspcntr = DISPPLANE_GAMMA_ENABLE; - if (intel_crtc->config.has_dp_encoder) intel_dp_set_m_n(intel_crtc); intel_set_pipe_timings(intel_crtc); - /* pipesrc and dspsize control the size that is scaled from, - * which should always be the user's requested size. - */ - I915_WRITE(DSPSIZE(plane), - ((intel_crtc->config.pipe_src_h - 1) << 16) | - (intel_crtc->config.pipe_src_w - 1)); - I915_WRITE(DSPPOS(plane), 0); - i9xx_set_pipeconf(intel_crtc); - I915_WRITE(DSPCNTR(plane), dspcntr); - POSTING_READ(DSPCNTR(plane)); - dev_priv->display.update_primary_plane(crtc, crtc->primary->fb, crtc->x, crtc->y); @@ -4725,8 +4710,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; - u32 dspcntr; WARN_ON(!crtc->enabled); @@ -4735,32 +4718,13 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) i9xx_set_pll_dividers(intel_crtc); - /* Set up the display plane register */ - dspcntr = DISPPLANE_GAMMA_ENABLE; - - if (pipe == 0) - dspcntr &= ~DISPPLANE_SEL_PIPE_MASK; - else - dspcntr |= DISPPLANE_SEL_PIPE_B; - if (intel_crtc->config.has_dp_encoder) intel_dp_set_m_n(intel_crtc); intel_set_pipe_timings(intel_crtc); - /* pipesrc and dspsize control the size that is scaled from, - * which should always be the user's requested size. - */ - I915_WRITE(DSPSIZE(plane), - ((intel_crtc->config.pipe_src_h - 1) << 16) | - (intel_crtc->config.pipe_src_w - 1)); - I915_WRITE(DSPPOS(plane), 0); - i9xx_set_pipeconf(intel_crtc); - I915_WRITE(DSPCNTR(plane), dspcntr); - POSTING_READ(DSPCNTR(plane)); - dev_priv->display.update_primary_plane(crtc, crtc->primary->fb, crtc->x, crtc->y); -- GitLab From fdd508a6419217cce28213f3c9bd27c02a0d4c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 8 Aug 2014 21:51:11 +0300 Subject: [PATCH 0104/5088] drm/i915: Call .update_primary_plane in intel_{enable, disable}_primary_hw_plane() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the intel_{enable,disable}_primary_hw_plane() simply call .update_primary_plane(), thus eliminating the rmw from these functions which should help the poor old 830M. Now we can also remove the .update_primary_plane() from the .crtc_enable() hooks because we end up calling it via intel_crtc_enable_planes()->intel_enable_primary_hw_plane(). This also has the nice benefit of making primary planes a bit closer to the way we handle sprite planes during modesets. v2: Just write 0 to DSPCNTR and DSPSURF/DSPADDR if the plane is (to be) disabled. Quicker, and more importantly avoids an oops when fb==NULL due to BIOS fb takeover failure. Pimp the commit message a bit (Matt) v3: Drop useless primary_enabled checks when setting DISPLAY_PLANE_ENABLE Reviewed-by: Matt Roper Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 119 +++++++++++---------------- 1 file changed, 49 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 041fd76a2ded..f306c91b74a5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2082,35 +2082,28 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv, /** * intel_enable_primary_hw_plane - enable the primary plane on a given pipe - * @dev_priv: i915 private structure - * @plane: plane to enable - * @pipe: pipe being fed + * @plane: plane to be enabled + * @crtc: crtc for the plane * - * Enable @plane on @pipe, making sure that @pipe is running first. + * Enable @plane on @crtc, making sure that the pipe is running first. */ -static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv, - enum plane plane, enum pipe pipe) +static void intel_enable_primary_hw_plane(struct drm_plane *plane, + struct drm_crtc *crtc) { - struct drm_device *dev = dev_priv->dev; - struct intel_crtc *intel_crtc = - to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - int reg; - u32 val; + 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, pipe); + assert_pipe_enabled(dev_priv, intel_crtc->pipe); if (intel_crtc->primary_enabled) return; intel_crtc->primary_enabled = true; - reg = DSPCNTR(plane); - val = I915_READ(reg); - WARN_ON(val & DISPLAY_PLANE_ENABLE); - - I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE); - intel_flush_primary_plane(dev_priv, plane); + dev_priv->display.update_primary_plane(crtc, plane->fb, + crtc->x, crtc->y); /* * BDW signals flip done immediately if the plane @@ -2123,31 +2116,27 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv, /** * intel_disable_primary_hw_plane - disable the primary hardware plane - * @dev_priv: i915 private structure - * @plane: plane to disable - * @pipe: pipe consuming the data + * @plane: plane to be disabled + * @crtc: crtc for the plane * - * Disable @plane; should be an independent operation. + * Disable @plane on @crtc, making sure that the pipe is running first. */ -static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv, - enum plane plane, enum pipe pipe) +static void intel_disable_primary_hw_plane(struct drm_plane *plane, + struct drm_crtc *crtc) { - struct intel_crtc *intel_crtc = - to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - int reg; - u32 val; + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + assert_pipe_enabled(dev_priv, intel_crtc->pipe); if (!intel_crtc->primary_enabled) return; intel_crtc->primary_enabled = false; - reg = DSPCNTR(plane); - val = I915_READ(reg); - WARN_ON((val & DISPLAY_PLANE_ENABLE) == 0); - - I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE); - intel_flush_primary_plane(dev_priv, plane); + dev_priv->display.update_primary_plane(crtc, plane->fb, + crtc->x, crtc->y); } static bool need_vtd_wa(struct drm_device *dev) @@ -2390,10 +2379,19 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, u32 dspcntr; u32 reg = DSPCNTR(plane); + if (!intel_crtc->primary_enabled) { + I915_WRITE(reg, 0); + if (INTEL_INFO(dev)->gen >= 4) + I915_WRITE(DSPSURF(plane), 0); + else + I915_WRITE(DSPADDR(plane), 0); + POSTING_READ(reg); + return; + } + dspcntr = DISPPLANE_GAMMA_ENABLE; - if (intel_crtc->primary_enabled) - dspcntr |= DISPLAY_PLANE_ENABLE; + dspcntr |= DISPLAY_PLANE_ENABLE; if (INTEL_INFO(dev)->gen < 4) { if (intel_crtc->pipe == PIPE_B) @@ -2487,10 +2485,16 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, u32 dspcntr; u32 reg = DSPCNTR(plane); + if (!intel_crtc->primary_enabled) { + I915_WRITE(reg, 0); + I915_WRITE(DSPSURF(plane), 0); + POSTING_READ(reg); + return; + } + dspcntr = DISPPLANE_GAMMA_ENABLE; - if (intel_crtc->primary_enabled) - dspcntr |= DISPLAY_PLANE_ENABLE; + dspcntr |= DISPLAY_PLANE_ENABLE; if (IS_HASWELL(dev) || IS_BROADWELL(dev)) dspcntr |= DISPPLANE_PIPE_CSC_ENABLE; @@ -3884,14 +3888,12 @@ static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) static void intel_crtc_enable_planes(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); int pipe = intel_crtc->pipe; - int plane = intel_crtc->plane; drm_vblank_on(dev, pipe); - intel_enable_primary_hw_plane(dev_priv, plane, pipe); + intel_enable_primary_hw_plane(crtc->primary, crtc); intel_enable_planes(crtc); intel_crtc_update_cursor(crtc, true); intel_crtc_dpms_overlay(intel_crtc, true); @@ -3928,7 +3930,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) intel_crtc_dpms_overlay(intel_crtc, false); intel_crtc_update_cursor(crtc, false); intel_disable_planes(crtc); - intel_disable_primary_hw_plane(dev_priv, plane, pipe); + intel_disable_primary_hw_plane(crtc->primary, crtc); /* * FIXME: Once we grow proper nuclear flip support out of this we need @@ -3968,9 +3970,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) ironlake_set_pipeconf(crtc); - dev_priv->display.update_primary_plane(crtc, crtc->primary->fb, - crtc->x, crtc->y); - intel_crtc->active = true; intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); @@ -4078,9 +4077,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_set_pipe_csc(crtc); - dev_priv->display.update_primary_plane(crtc, crtc->primary->fb, - crtc->x, crtc->y); - intel_crtc->active = true; intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); @@ -4629,7 +4625,6 @@ static void valleyview_modeset_global_resources(struct drm_device *dev) static void valleyview_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; @@ -4656,9 +4651,6 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) i9xx_set_pipeconf(intel_crtc); - dev_priv->display.update_primary_plane(crtc, crtc->primary->fb, - crtc->x, crtc->y); - intel_crtc->active = true; intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); @@ -4706,7 +4698,6 @@ static void i9xx_set_pll_dividers(struct intel_crtc *crtc) static void i9xx_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; @@ -4725,9 +4716,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) i9xx_set_pipeconf(intel_crtc); - dev_priv->display.update_primary_plane(crtc, crtc->primary->fb, - crtc->x, crtc->y); - intel_crtc->active = true; if (!IS_GEN2(dev)) @@ -11351,7 +11339,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) ret = intel_set_mode(set->crtc, set->mode, set->x, set->y, set->fb); } else if (config->fb_changed) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); intel_crtc_wait_for_pending_flips(set->crtc); @@ -11365,8 +11352,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) */ if (!intel_crtc->primary_enabled && ret == 0) { WARN_ON(!intel_crtc->active); - intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane, - intel_crtc->pipe); + intel_enable_primary_hw_plane(set->crtc->primary, set->crtc); } /* @@ -11519,8 +11505,6 @@ static int intel_primary_plane_disable(struct drm_plane *plane) { struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc; if (!plane->fb) @@ -11543,8 +11527,8 @@ intel_primary_plane_disable(struct drm_plane *plane) goto disable_unpin; intel_crtc_wait_for_pending_flips(plane->crtc); - intel_disable_primary_hw_plane(dev_priv, intel_plane->plane, - intel_plane->pipe); + intel_disable_primary_hw_plane(plane, plane->crtc); + disable_unpin: mutex_lock(&dev->struct_mutex); i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, @@ -11564,9 +11548,7 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_w, uint32_t src_h) { 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_plane *intel_plane = to_intel_plane(plane); struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); struct drm_rect dest = { @@ -11653,9 +11635,7 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe)); if (intel_crtc->primary_enabled) - intel_disable_primary_hw_plane(dev_priv, - intel_plane->plane, - intel_plane->pipe); + intel_disable_primary_hw_plane(plane, crtc); if (plane->fb != fb) @@ -11672,8 +11652,7 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc, return ret; if (!intel_crtc->primary_enabled) - intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane, - intel_crtc->pipe); + intel_enable_primary_hw_plane(plane, crtc); return 0; } -- GitLab From fd5c9d230d2ac8a2594dfd15f0cca678fd7a64c7 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 7 Aug 2014 20:52:33 +0400 Subject: [PATCH 0105/5088] Smack: fix behavior of smack_inode_listsecurity Security operation ->inode_listsecurity is used for generating list of available extended attributes for syscall listxattr. Currently it's used only in nfs4 or if filesystem doesn't provide i_op->listxattr. The list is the set of NULL-terminated names, one after the other. This method must include zero byte at the and into result. Also this function must return length even if string does not fit into output buffer or it is NULL, see similar method in selinux and man listxattr. Signed-off-by: Konstantin Khlebnikov --- security/smack/smack_lsm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index e6ab307ce86e..b11ab23b328b 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1122,13 +1122,12 @@ static int smack_inode_getsecurity(const struct inode *inode, static int smack_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size) { - int len = strlen(XATTR_NAME_SMACK); + int len = sizeof(XATTR_NAME_SMACK); - if (buffer != NULL && len <= buffer_size) { + if (buffer != NULL && len <= buffer_size) memcpy(buffer, XATTR_NAME_SMACK, len); - return len; - } - return -EINVAL; + + return len; } /** -- GitLab From b862e561bad6372872f5bf98d95f4131d265b110 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 7 Aug 2014 20:52:43 +0400 Subject: [PATCH 0106/5088] Smack: handle zero-length security labels without panic Zero-length security labels are invalid but kernel should handle them. This patch fixes kernel panic after setting zero-length security labels: # attr -S -s "SMACK64" -V "" file And after writing zero-length string into smackfs files syslog and onlycp: # python -c 'import os; os.write(1, "")' > /smack/syslog The problem is caused by brain-damaged logic in function smk_parse_smack() which takes pointer to buffer and its length but if length below or equal zero it thinks that the buffer is zero-terminated. Unfortunately callers of this function are widely used and proper fix requires serious refactoring. Signed-off-by: Konstantin Khlebnikov --- security/smack/smack_lsm.c | 2 +- security/smack/smackfs.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index b11ab23b328b..afa5ad0e7f72 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -923,7 +923,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, rc = -EPERM; if (rc == 0 && check_import) { - skp = smk_import_entry(value, size); + skp = size ? smk_import_entry(value, size) : NULL; if (skp == NULL || (check_star && (skp == &smack_known_star || skp == &smack_known_web))) rc = -EINVAL; diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 3c720ff10591..56a1439786a9 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -1677,7 +1677,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, if (smack_onlycap != NULL && smack_onlycap != skp) return -EPERM; - data = kzalloc(count, GFP_KERNEL); + data = kzalloc(count + 1, GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -2228,7 +2228,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf, if (!smack_privileged(CAP_MAC_ADMIN)) return -EPERM; - data = kzalloc(count, GFP_KERNEL); + data = kzalloc(count + 1, GFP_KERNEL); if (data == NULL) return -ENOMEM; -- GitLab From da1b63566c469bf3e2b24182114422e16b1aa34c Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 7 Aug 2014 20:52:49 +0400 Subject: [PATCH 0107/5088] Smack: remove unneeded NULL-termination from securtity label Values of extended attributes are stored as binary blobs. NULL-termination of them isn't required. It just wastes disk space and confuses command-line tools like getfattr because they have to print that zero byte at the end. This patch removes terminating zero byte from initial security label in smack_inode_init_security and cuts it out in function smack_inode_getsecurity which is used by syscall getxattr. This change seems completely safe, because function smk_parse_smack ignores everything after first zero byte. Signed-off-by: Konstantin Khlebnikov --- security/smack/smack_lsm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index afa5ad0e7f72..16ae8534b14c 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -672,7 +672,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, } if (len) - *len = strlen(isp) + 1; + *len = strlen(isp); return 0; } @@ -1076,7 +1076,7 @@ static int smack_inode_getsecurity(const struct inode *inode, if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { isp = smk_of_inode(inode); - ilen = strlen(isp) + 1; + ilen = strlen(isp); *buffer = isp; return ilen; } @@ -1101,7 +1101,7 @@ static int smack_inode_getsecurity(const struct inode *inode, else return -EOPNOTSUPP; - ilen = strlen(isp) + 1; + ilen = strlen(isp); if (rc == 0) { *buffer = isp; rc = ilen; -- GitLab From 22c59960d9fe72f3fbd28de69cc43c5522dd5fe6 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 8 Aug 2014 17:45:32 -0300 Subject: [PATCH 0108/5088] drm/i915: fix i915_interrupt_info on BDW Currently, if the machine is runtime suspended an you read the file, you will get an "Unclaimed register" error message. Testcase: igt/pm_rpm/debugfs-read Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 330caa1ab9f9..3b7decbeeed3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -703,6 +703,12 @@ static int i915_interrupt_info(struct seq_file *m, void *data) } for_each_pipe(pipe) { + if (!intel_display_power_enabled(dev_priv, + POWER_DOMAIN_PIPE(pipe))) { + seq_printf(m, "Pipe %c power disabled\n", + pipe_name(pipe)); + continue; + } seq_printf(m, "Pipe %c IMR:\t%08x\n", pipe_name(pipe), I915_READ(GEN8_DE_PIPE_IMR(pipe))); -- GitLab From fd3cbdc0d1b5254a2e8793df58c409b469899a3f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 10 Aug 2014 08:53:39 +0200 Subject: [PATCH 0109/5088] jump_label: Fix small typos in the documentation Was reading through the documentation of this code and noticed a few typos, missing commas, etc. Cc: Jason Baron Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Borislav Petkov Cc: Andrew Morton Cc: Linus Torvalds Cc: Thomas Gleixner Cc: Mel Gorman Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- include/linux/jump_label.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index 784304b222b3..98f923b6a0ea 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h @@ -8,28 +8,28 @@ * Copyright (C) 2011-2012 Peter Zijlstra * * Jump labels provide an interface to generate dynamic branches using - * self-modifying code. Assuming toolchain and architecture support the result - * of a "if (static_key_false(&key))" statement is a unconditional branch (which + * self-modifying code. Assuming toolchain and architecture support, the result + * of a "if (static_key_false(&key))" statement is an unconditional branch (which * defaults to false - and the true block is placed out of line). * * However at runtime we can change the branch target using * static_key_slow_{inc,dec}(). These function as a 'reference' count on the key - * object and for as long as there are references all branches referring to + * object, and for as long as there are references all branches referring to * that particular key will point to the (out of line) true block. * - * Since this relies on modifying code the static_key_slow_{inc,dec}() functions + * Since this relies on modifying code, the static_key_slow_{inc,dec}() functions * must be considered absolute slow paths (machine wide synchronization etc.). - * OTOH, since the affected branches are unconditional their runtime overhead + * OTOH, since the affected branches are unconditional, their runtime overhead * will be absolutely minimal, esp. in the default (off) case where the total * effect is a single NOP of appropriate size. The on case will patch in a jump * to the out-of-line block. * - * When the control is directly exposed to userspace it is prudent to delay the + * When the control is directly exposed to userspace, it is prudent to delay the * decrement to avoid high frequency code modifications which can (and do) * cause significant performance degradation. Struct static_key_deferred and * static_key_slow_dec_deferred() provide for this. * - * Lacking toolchain and or architecture support, it falls back to a simple + * Lacking toolchain and or architecture support, jump labels fall back to a simple * conditional branch. * * struct static_key my_key = STATIC_KEY_INIT_TRUE; @@ -43,8 +43,7 @@ * * Not initializing the key (static data is initialized to 0s anyway) is the * same as using STATIC_KEY_INIT_FALSE. - * -*/ + */ #include #include -- GitLab From 3bb11b536c1037143765b4efc8056600438df7f6 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Mon, 11 Aug 2014 09:06:39 +0530 Subject: [PATCH 0110/5088] drm/i915: Continuation of future readiness series Removing the check for HAS_PCH_SPLIT, it looks redundant here. Anyways all the platforms are checked separately. v2: Reordering as per the gen (Ville) Signed-off-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 42 +++++++++++++--------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f306c91b74a5..0746590ed4e3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12354,29 +12354,27 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.get_display_clock_speed = i830_get_display_clock_speed; - if (HAS_PCH_SPLIT(dev)) { - if (IS_GEN5(dev)) { - dev_priv->display.fdi_link_train = ironlake_fdi_link_train; - dev_priv->display.write_eld = ironlake_write_eld; - } else if (IS_GEN6(dev)) { - dev_priv->display.fdi_link_train = gen6_fdi_link_train; - dev_priv->display.write_eld = ironlake_write_eld; - dev_priv->display.modeset_global_resources = - snb_modeset_global_resources; - } else if (IS_IVYBRIDGE(dev)) { - /* FIXME: detect B0+ stepping and use auto training */ - dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; - dev_priv->display.write_eld = ironlake_write_eld; - dev_priv->display.modeset_global_resources = - ivb_modeset_global_resources; - } else if (IS_HASWELL(dev) || IS_GEN8(dev)) { - dev_priv->display.fdi_link_train = hsw_fdi_link_train; - dev_priv->display.write_eld = haswell_write_eld; - dev_priv->display.modeset_global_resources = - haswell_modeset_global_resources; - } - } else if (IS_G4X(dev)) { + if (IS_G4X(dev)) { dev_priv->display.write_eld = g4x_write_eld; + } else if (IS_GEN5(dev)) { + dev_priv->display.fdi_link_train = ironlake_fdi_link_train; + dev_priv->display.write_eld = ironlake_write_eld; + } else if (IS_GEN6(dev)) { + dev_priv->display.fdi_link_train = gen6_fdi_link_train; + dev_priv->display.write_eld = ironlake_write_eld; + dev_priv->display.modeset_global_resources = + snb_modeset_global_resources; + } else if (IS_IVYBRIDGE(dev)) { + /* FIXME: detect B0+ stepping and use auto training */ + dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; + dev_priv->display.write_eld = ironlake_write_eld; + dev_priv->display.modeset_global_resources = + ivb_modeset_global_resources; + } else if (IS_HASWELL(dev) || IS_GEN8(dev)) { + dev_priv->display.fdi_link_train = hsw_fdi_link_train; + dev_priv->display.write_eld = haswell_write_eld; + dev_priv->display.modeset_global_resources = + haswell_modeset_global_resources; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.modeset_global_resources = valleyview_modeset_global_resources; -- GitLab From d6699dd3a7f696a80a5f8e5bb6ecf6ff6dd7c998 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Sat, 9 Aug 2014 16:29:31 +0100 Subject: [PATCH 0111/5088] drm/i915: Fix wrong number of HDMI translation entries I keep telling myself that those tables aren't great because their size is the number of dwords we need to program and not the number of entries (number of dwords = number of entries * 2). And... I got it wrong when I refactored the code. Fortunately, it was only wrong when the VBT table (or the code parsing it) is itself erroneous. Long story short, it shouldn't matter, but still, there's a potential array overflow and random programming of the DDI translation tables. Cc: Paulo Zanoni Signed-off-by: Damien Lespiau Reviewed-by: Jani Nikula 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 ca1f9a8a7d03..02d55843c78d 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -169,14 +169,14 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) ddi_translations_dp = bdw_ddi_translations_dp; ddi_translations_edp = bdw_ddi_translations_edp; ddi_translations_hdmi = bdw_ddi_translations_hdmi; - n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); + n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi) / 2; hdmi_800mV_0dB = 7; } else if (IS_HASWELL(dev)) { ddi_translations_fdi = hsw_ddi_translations_fdi; ddi_translations_dp = hsw_ddi_translations_dp; ddi_translations_edp = hsw_ddi_translations_dp; ddi_translations_hdmi = hsw_ddi_translations_hdmi; - n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); + n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi) / 2; hdmi_800mV_0dB = 6; } else { WARN(1, "ddi translation table missing\n"); @@ -184,7 +184,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) ddi_translations_fdi = bdw_ddi_translations_fdi; ddi_translations_dp = bdw_ddi_translations_dp; ddi_translations_hdmi = bdw_ddi_translations_hdmi; - n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); + n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi) / 2; hdmi_800mV_0dB = 7; } -- GitLab From dc8cd1e790081a31ba4d86c3c0812c348eeec7fc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 9 Aug 2014 17:37:22 +0100 Subject: [PATCH 0112/5088] drm/i915: Only perform set-to-gtt domain for objects bound to the global gtt If an object is not bound into the global GTT, then it cannot be accessed via the GTT. This restores the original code that was muddled by ppGTT. In the process, we remove a WARN that had long outlived its usefulness and was simply being coded around instead. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 20743bd421f9..1be7e541a7c7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3592,11 +3592,12 @@ int i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + struct i915_vma *vma = i915_gem_obj_to_ggtt(obj); uint32_t old_write_domain, old_read_domains; int ret; /* Not valid to be called on unbound objects. */ - if (!i915_gem_obj_bound_any(obj)) + if (vma == NULL) return -EINVAL; if (obj->base.write_domain == I915_GEM_DOMAIN_GTT) @@ -3638,13 +3639,9 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) old_write_domain); /* And bump the LRU for this access */ - if (i915_gem_object_is_inactive(obj)) { - struct i915_vma *vma = i915_gem_obj_to_ggtt(obj); - if (vma) - list_move_tail(&vma->mm_list, - &dev_priv->gtt.base.inactive_list); - - } + if (i915_gem_object_is_inactive(obj)) + list_move_tail(&vma->mm_list, + &dev_priv->gtt.base.inactive_list); return 0; } @@ -3808,9 +3805,6 @@ static bool is_pin_display(struct drm_i915_gem_object *obj) { struct i915_vma *vma; - if (list_empty(&obj->vma_list)) - return false; - vma = i915_gem_obj_to_ggtt(obj); if (!vma) return false; @@ -5253,12 +5247,6 @@ struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj) { struct i915_vma *vma; - /* This WARN has probably outlived its usefulness (callers already - * WARN if they don't find the GGTT vma they expect). When removing, - * remember to remove the pre-check in is_pin_display() as well */ - if (WARN_ON(list_empty(&obj->vma_list))) - return NULL; - vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link); if (vma->vm != obj_to_ggtt(obj)) return NULL; -- GitLab From e6a844687cf929ec053c7578d5ecc794a8a6c5cf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 11 Aug 2014 12:00:12 +0200 Subject: [PATCH 0113/5088] drm/i915: Force CPU relocations if not GTT mapped Move the decision on whether we need to have a mappable object during execbuffer to the fore and then reuse that decision by propagating the flag through to reservation. As a corollary, before doing the actual relocation through the GTT, we can make sure that we do have a GTT mapping through which to operate. Note that the key to make this work is to ditch the obj->map_and_fenceable unbind optimization - with full ppgtt it doesn't make a lot of sense any more anyway. v2: Revamp and resend to ease future patches. v3: Refresh patch rationale References: https://bugs.freedesktop.org/show_bug.cgi?id=81094 Signed-off-by: Chris Wilson Cc: Ben Widawsky Cc: Daniel Vetter [danvet: Explain why obj->map_and_fenceable is key and split out the secure batch fix.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 8 +-- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 59 +++++++++++----------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1be7e541a7c7..1ca2231e3929 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2928,9 +2928,8 @@ int i915_vma_unbind(struct i915_vma *vma) vma->unbind_vma(vma); list_del_init(&vma->mm_list); - /* Avoid an unnecessary call to unbind on rebind. */ if (i915_is_ggtt(vma->vm)) - obj->map_and_fenceable = true; + obj->map_and_fenceable = false; drm_mm_remove_node(&vma->node); i915_gem_vma_destroy(vma); @@ -3282,6 +3281,9 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) 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); @@ -4331,8 +4333,6 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, obj->fence_reg = I915_FENCE_REG_NONE; obj->madv = I915_MADV_WILLNEED; - /* Avoid an unnecessary call to unbind on the first bind. */ - obj->map_and_fenceable = true; i915_gem_info_add_obj(obj->base.dev->dev_private, obj->base.size); } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 60998fc4e5b2..6320a385841b 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -35,6 +35,7 @@ #define __EXEC_OBJECT_HAS_PIN (1<<31) #define __EXEC_OBJECT_HAS_FENCE (1<<30) +#define __EXEC_OBJECT_NEEDS_MAP (1<<29) #define __EXEC_OBJECT_NEEDS_BIAS (1<<28) #define BATCH_OFFSET_BIAS (256*1024) @@ -534,14 +535,6 @@ i915_gem_execbuffer_relocate(struct eb_vmas *eb) return ret; } -static int -need_reloc_mappable(struct i915_vma *vma) -{ - struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; - return entry->relocation_count && !use_cpu_reloc(vma->obj) && - i915_is_ggtt(vma->vm); -} - static int i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, struct intel_engine_cs *ring, @@ -550,19 +543,12 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, struct drm_i915_gem_object *obj = vma->obj; struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; - bool need_fence; uint64_t flags; int ret; flags = 0; - - need_fence = - has_fenced_gpu_access && - entry->flags & EXEC_OBJECT_NEEDS_FENCE && - obj->tiling_mode != I915_TILING_NONE; - if (need_fence || need_reloc_mappable(vma)) + if (entry->flags & __EXEC_OBJECT_NEEDS_MAP) flags |= PIN_MAPPABLE; - if (entry->flags & EXEC_OBJECT_NEEDS_GTT) flags |= PIN_GLOBAL; if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS) @@ -601,26 +587,40 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, } static bool -eb_vma_misplaced(struct i915_vma *vma, bool has_fenced_gpu_access) +need_reloc_mappable(struct i915_vma *vma) { struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; - struct drm_i915_gem_object *obj = vma->obj; - bool need_fence, need_mappable; - need_fence = - has_fenced_gpu_access && - entry->flags & EXEC_OBJECT_NEEDS_FENCE && - obj->tiling_mode != I915_TILING_NONE; - need_mappable = need_fence || need_reloc_mappable(vma); + if (entry->relocation_count == 0) + return false; + + if (!i915_is_ggtt(vma->vm)) + return false; + + /* See also use_cpu_reloc() */ + if (HAS_LLC(vma->obj->base.dev)) + return false; + + if (vma->obj->base.write_domain == I915_GEM_DOMAIN_CPU) + return false; - WARN_ON((need_mappable || need_fence) && + return true; +} + +static bool +eb_vma_misplaced(struct i915_vma *vma) +{ + struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; + struct drm_i915_gem_object *obj = vma->obj; + + WARN_ON(entry->flags & __EXEC_OBJECT_NEEDS_MAP && !i915_is_ggtt(vma->vm)); if (entry->alignment && vma->node.start & (entry->alignment - 1)) return true; - if (need_mappable && !obj->map_and_fenceable) + if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable) return true; if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS && @@ -664,9 +664,10 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, obj->tiling_mode != I915_TILING_NONE; need_mappable = need_fence || need_reloc_mappable(vma); - if (need_mappable) + if (need_mappable) { + entry->flags |= __EXEC_OBJECT_NEEDS_MAP; list_move(&vma->exec_list, &ordered_vmas); - else + } else list_move_tail(&vma->exec_list, &ordered_vmas); obj->base.pending_read_domains = I915_GEM_GPU_DOMAINS & ~I915_GEM_DOMAIN_COMMAND; @@ -696,7 +697,7 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, if (!drm_mm_node_allocated(&vma->node)) continue; - if (eb_vma_misplaced(vma, has_fenced_gpu_access)) + if (eb_vma_misplaced(vma)) ret = i915_vma_unbind(vma); else ret = i915_gem_execbuffer_reserve_vma(vma, ring, need_relocs); -- GitLab From 82b6b6d786466e705e7244cc676189ce47a9199a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 9 Aug 2014 17:37:24 +0100 Subject: [PATCH 0114/5088] drm/i915: Remove fenced_gpu_access and pending_fenced_gpu_access This migrates the fence tracking onto the existing seqno infrastructure so that the later conversion to tracking via requests is simplified. Signed-off-by: Chris Wilson 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 | 34 ++++++++++++---------- drivers/gpu/drm/i915/i915_gem_tiling.c | 2 +- 4 files changed, 20 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fab97bc3215f..5c3f033ff928 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1777,13 +1777,6 @@ struct drm_i915_gem_object { * Only honoured if hardware has relevant pte bit */ unsigned long gt_ro:1; - - /* - * Is the GPU currently using a fence to access this buffer, - */ - unsigned int pending_fenced_gpu_access:1; - unsigned int fenced_gpu_access:1; - unsigned int cache_level:3; unsigned int has_aliasing_ppgtt_mapping:1; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1ca2231e3929..3eec344bdac0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2161,8 +2161,6 @@ static void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_engine_cs *ring) { - struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; u32 seqno = intel_ring_get_seqno(ring); BUG_ON(ring == NULL); @@ -2181,19 +2179,6 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, list_move_tail(&obj->ring_list, &ring->active_list); obj->last_read_seqno = seqno; - - if (obj->fenced_gpu_access) { - obj->last_fenced_seqno = seqno; - - /* Bump MRU to take account of the delayed flush */ - if (obj->fence_reg != I915_FENCE_REG_NONE) { - struct drm_i915_fence_reg *reg; - - reg = &dev_priv->fence_regs[obj->fence_reg]; - list_move_tail(®->lru_list, - &dev_priv->mm.fence_list); - } - } } void i915_vma_move_to_active(struct i915_vma *vma, @@ -2229,7 +2214,6 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) obj->base.write_domain = 0; obj->last_fenced_seqno = 0; - obj->fenced_gpu_access = false; obj->active = 0; drm_gem_object_unreference(&obj->base); @@ -3174,7 +3158,6 @@ i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) obj->last_fenced_seqno = 0; } - obj->fenced_gpu_access = false; return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6320a385841b..70946c551e5d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -542,7 +542,6 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, { struct drm_i915_gem_object *obj = vma->obj; struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; - bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; uint64_t flags; int ret; @@ -560,17 +559,13 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, entry->flags |= __EXEC_OBJECT_HAS_PIN; - if (has_fenced_gpu_access) { - if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) { - ret = i915_gem_object_get_fence(obj); - if (ret) - return ret; - - if (i915_gem_object_pin_fence(obj)) - entry->flags |= __EXEC_OBJECT_HAS_FENCE; + if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) { + ret = i915_gem_object_get_fence(obj); + if (ret) + return ret; - obj->pending_fenced_gpu_access = true; - } + if (i915_gem_object_pin_fence(obj)) + entry->flags |= __EXEC_OBJECT_HAS_FENCE; } if (entry->offset != vma->node.start) { @@ -658,8 +653,9 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, obj = vma->obj; entry = vma->exec_entry; + if (!has_fenced_gpu_access) + entry->flags &= ~EXEC_OBJECT_NEEDS_FENCE; need_fence = - has_fenced_gpu_access && entry->flags & EXEC_OBJECT_NEEDS_FENCE && obj->tiling_mode != I915_TILING_NONE; need_mappable = need_fence || need_reloc_mappable(vma); @@ -672,7 +668,6 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, obj->base.pending_read_domains = I915_GEM_GPU_DOMAINS & ~I915_GEM_DOMAIN_COMMAND; obj->base.pending_write_domain = 0; - obj->pending_fenced_gpu_access = false; } list_splice(&ordered_vmas, vmas); @@ -959,9 +954,11 @@ static void i915_gem_execbuffer_move_to_active(struct list_head *vmas, struct intel_engine_cs *ring) { + u32 seqno = intel_ring_get_seqno(ring); struct i915_vma *vma; list_for_each_entry(vma, vmas, exec_list) { + struct drm_i915_gem_exec_object2 *entry = vma->exec_entry; struct drm_i915_gem_object *obj = vma->obj; u32 old_read = obj->base.read_domains; u32 old_write = obj->base.write_domain; @@ -970,18 +967,25 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, if (obj->base.write_domain == 0) obj->base.pending_read_domains |= obj->base.read_domains; obj->base.read_domains = obj->base.pending_read_domains; - obj->fenced_gpu_access = obj->pending_fenced_gpu_access; i915_vma_move_to_active(vma, ring); if (obj->base.write_domain) { obj->dirty = 1; - obj->last_write_seqno = intel_ring_get_seqno(ring); + obj->last_write_seqno = seqno; intel_fb_obj_invalidate(obj, ring); /* update for the implicit flush after a batch */ obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; } + if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) { + obj->last_fenced_seqno = seqno; + if (entry->flags & __EXEC_OBJECT_HAS_FENCE) { + struct drm_i915_private *dev_priv = to_i915(ring->dev); + list_move_tail(&dev_priv->fence_regs[obj->fence_reg].lru_list, + &dev_priv->mm.fence_list); + } + } trace_i915_gem_object_change_domain(obj, old_read, old_write); } diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index cb150e8b4336..7e623bf097a1 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -376,7 +376,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, if (ret == 0) { obj->fence_dirty = - obj->fenced_gpu_access || + obj->last_fenced_seqno || obj->fence_reg != I915_FENCE_REG_NONE; obj->tiling_mode = args->tiling_mode; -- GitLab From 87f1f46514babd40fc3551ca2d6148cdedd9c7e3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 9 Aug 2014 19:18:42 +0100 Subject: [PATCH 0115/5088] drm/i915: Copy PCI device id into the device info block This is so that we can make the drm_i915_private->info always the preferred source for chipset type and feature queries. Signed-off-by: Chris Wilson Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 5 ++-- drivers/gpu/drm/i915/i915_drv.h | 50 +++++++++++++++++---------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index c965698a8bac..1867e2619e73 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1603,9 +1603,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev->dev_private = dev_priv; dev_priv->dev = dev; - /* copy initial configuration to dev_priv->info */ + /* Setup the write-once "constant" device info */ device_info = (struct intel_device_info *)&dev_priv->info; - *device_info = *info; + memcpy(device_info, info, sizeof(dev_priv->info)); + device_info->device_id = dev->pdev->device; spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->gpu_error.lock); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5c3f033ff928..8a55f07d80cb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -558,6 +558,7 @@ struct intel_uncore { struct intel_device_info { u32 display_mmio_offset; + u16 device_id; u8 num_pipes:3; u8 num_sprites[I915_MAX_PIPES]; u8 gen; @@ -1980,51 +1981,52 @@ struct drm_i915_cmd_table { int count; }; -#define INTEL_INFO(dev) (&to_i915(dev)->info) +#define INTEL_INFO(p) (&to_i915(p)->info) +#define INTEL_DEVID(p) (INTEL_INFO(p)->device_id) -#define IS_I830(dev) ((dev)->pdev->device == 0x3577) -#define IS_845G(dev) ((dev)->pdev->device == 0x2562) +#define IS_I830(dev) (INTEL_DEVID(dev) == 0x3577) +#define IS_845G(dev) (INTEL_DEVID(dev) == 0x2562) #define IS_I85X(dev) (INTEL_INFO(dev)->is_i85x) -#define IS_I865G(dev) ((dev)->pdev->device == 0x2572) +#define IS_I865G(dev) (INTEL_DEVID(dev) == 0x2572) #define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g) -#define IS_I915GM(dev) ((dev)->pdev->device == 0x2592) -#define IS_I945G(dev) ((dev)->pdev->device == 0x2772) +#define IS_I915GM(dev) (INTEL_DEVID(dev) == 0x2592) +#define IS_I945G(dev) (INTEL_DEVID(dev) == 0x2772) #define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm) #define IS_BROADWATER(dev) (INTEL_INFO(dev)->is_broadwater) #define IS_CRESTLINE(dev) (INTEL_INFO(dev)->is_crestline) -#define IS_GM45(dev) ((dev)->pdev->device == 0x2A42) +#define IS_GM45(dev) (INTEL_DEVID(dev) == 0x2A42) #define IS_G4X(dev) (INTEL_INFO(dev)->is_g4x) -#define IS_PINEVIEW_G(dev) ((dev)->pdev->device == 0xa001) -#define IS_PINEVIEW_M(dev) ((dev)->pdev->device == 0xa011) +#define IS_PINEVIEW_G(dev) (INTEL_DEVID(dev) == 0xa001) +#define IS_PINEVIEW_M(dev) (INTEL_DEVID(dev) == 0xa011) #define IS_PINEVIEW(dev) (INTEL_INFO(dev)->is_pineview) #define IS_G33(dev) (INTEL_INFO(dev)->is_g33) -#define IS_IRONLAKE_M(dev) ((dev)->pdev->device == 0x0046) +#define IS_IRONLAKE_M(dev) (INTEL_DEVID(dev) == 0x0046) #define IS_IVYBRIDGE(dev) (INTEL_INFO(dev)->is_ivybridge) -#define IS_IVB_GT1(dev) ((dev)->pdev->device == 0x0156 || \ - (dev)->pdev->device == 0x0152 || \ - (dev)->pdev->device == 0x015a) -#define IS_SNB_GT1(dev) ((dev)->pdev->device == 0x0102 || \ - (dev)->pdev->device == 0x0106 || \ - (dev)->pdev->device == 0x010A) +#define IS_IVB_GT1(dev) (INTEL_DEVID(dev) == 0x0156 || \ + INTEL_DEVID(dev) == 0x0152 || \ + INTEL_DEVID(dev) == 0x015a) +#define IS_SNB_GT1(dev) (INTEL_DEVID(dev) == 0x0102 || \ + INTEL_DEVID(dev) == 0x0106 || \ + INTEL_DEVID(dev) == 0x010A) #define IS_VALLEYVIEW(dev) (INTEL_INFO(dev)->is_valleyview) #define IS_CHERRYVIEW(dev) (INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev)) #define IS_HASWELL(dev) (INTEL_INFO(dev)->is_haswell) #define IS_BROADWELL(dev) (!INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev)) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) #define IS_HSW_EARLY_SDV(dev) (IS_HASWELL(dev) && \ - ((dev)->pdev->device & 0xFF00) == 0x0C00) + (INTEL_DEVID(dev) & 0xFF00) == 0x0C00) #define IS_BDW_ULT(dev) (IS_BROADWELL(dev) && \ - (((dev)->pdev->device & 0xf) == 0x2 || \ - ((dev)->pdev->device & 0xf) == 0x6 || \ - ((dev)->pdev->device & 0xf) == 0xe)) + ((INTEL_DEVID(dev) & 0xf) == 0x2 || \ + (INTEL_DEVID(dev) & 0xf) == 0x6 || \ + (INTEL_DEVID(dev) & 0xf) == 0xe)) #define IS_HSW_ULT(dev) (IS_HASWELL(dev) && \ - ((dev)->pdev->device & 0xFF00) == 0x0A00) + (INTEL_DEVID(dev) & 0xFF00) == 0x0A00) #define IS_ULT(dev) (IS_HSW_ULT(dev) || IS_BDW_ULT(dev)) #define IS_HSW_GT3(dev) (IS_HASWELL(dev) && \ - ((dev)->pdev->device & 0x00F0) == 0x0020) + (INTEL_DEVID(dev) & 0x00F0) == 0x0020) /* ULX machines are also considered ULT. */ -#define IS_HSW_ULX(dev) ((dev)->pdev->device == 0x0A0E || \ - (dev)->pdev->device == 0x0A1E) +#define IS_HSW_ULX(dev) (INTEL_DEVID(dev) == 0x0A0E || \ + INTEL_DEVID(dev) == 0x0A1E) #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary) /* -- GitLab From f6daaec29b2a201eb8db2ce26b4460b779ad8111 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Sat, 9 Aug 2014 23:00:56 +0100 Subject: [PATCH 0116/5088] drm/i915: Make intel_disable_shared_dpll() static Found with sparse. Signed-off-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 0746590ed4e3..245cf4128314 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1797,7 +1797,7 @@ static void intel_enable_shared_dpll(struct intel_crtc *crtc) pll->on = true; } -void intel_disable_shared_dpll(struct intel_crtc *crtc) +static void intel_disable_shared_dpll(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; -- GitLab From 1bee20175f27b46427f10290fdd4a79334d41a60 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Sat, 9 Aug 2014 23:00:58 +0100 Subject: [PATCH 0117/5088] drm/i915: Remove set but unused 'gt_perf_status' Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 41de760bf1d4..12f4e143328c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3719,7 +3719,6 @@ static void gen6_enable_rps(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring; u32 rp_state_cap; - u32 gt_perf_status; u32 rc6vids, pcu_mbox = 0, rc6_mask = 0; u32 gtfifodbg; int rc6_mode; @@ -3744,7 +3743,6 @@ static void gen6_enable_rps(struct drm_device *dev) gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); parse_rp_state_cap(dev_priv, rp_state_cap); -- GitLab From 9bec9b1334d687c0a9fcf3d3a1987a61b4826a45 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 11 Aug 2014 09:21:35 +0100 Subject: [PATCH 0118/5088] drm/i915: Double check ring is idle before declaring the GPU wedged During ring initialisation, sometimes we observe, though not in production hardware, that the idle flag is not set even though the ring is empty. Double check before giving up. Signed-off-by: Chris Wilson Cc: Damien Lespiau Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 117543e58d48..a059b64a0fb2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -478,7 +478,12 @@ static bool stop_ring(struct intel_engine_cs *ring) I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING)); if (wait_for((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) { DRM_ERROR("%s : timed out trying to stop ring\n", ring->name); - return false; + /* Sometimes we observe that the idle flag is not + * set even though the ring is empty. So double + * check before giving up. + */ + if (I915_READ_HEAD(ring) != I915_READ_TAIL(ring)) + return false; } } -- GitLab From dbbe91279511d6a18a521b953a3c139e4787e660 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 9 Aug 2014 19:18:43 +0100 Subject: [PATCH 0119/5088] drm/i915: Agnostic INTEL_INFO Adapt the macro so that we can pass either the struct drm_device or the struct drm_i915_private pointers and get the answer we want. Over time, my plan is to convert all users over to using drm_i915_private and so trimming down the pointer dance. Having spent a few hours chasing that goal and achieved over 8k of object code saving, it appears to be a worthwhile target. This interim macro allows us to slowly convert over. Signed-off-by: Chris Wilson [danvet: Drop the (struct drm_device *) cast per the m-l discussion. Also explain the seemingly unecessary first cast.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 1867e2619e73..1763fbf34e1d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1596,6 +1596,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (!drm_core_check_feature(dev, DRIVER_MODESET) && !dev->agp) return -EINVAL; + /* For the ugly agnostic INTEL_INFO macro */ + BUILD_BUG_ON(sizeof(*dev_priv) == sizeof(*dev)); + dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8a55f07d80cb..6959c1b2d648 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1981,7 +1981,10 @@ struct drm_i915_cmd_table { int count; }; -#define INTEL_INFO(p) (&to_i915(p)->info) +/* Note that the (struct drm_i915_private *) cast is just to shut up gcc. */ +#define __I915__(p) ((sizeof(*(p)) == sizeof(struct drm_i915_private)) ? \ + (struct drm_i915_private *)(p) : to_i915(p)) +#define INTEL_INFO(p) (&__I915__(p)->info) #define INTEL_DEVID(p) (INTEL_INFO(p)->device_id) #define IS_I830(dev) (INTEL_DEVID(dev) == 0x3577) -- GitLab From da51a1e7e398129d9fddd4b26b8469145dd4fd08 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 11 Aug 2014 12:08:58 +0200 Subject: [PATCH 0120/5088] drm/i915: Fix secure dispatch with full ppgtt Based upon a hunk from a patch from Chris Wilson, but augmented to: - Process the batch in the full ppgtt vm so that self-relocations match again with userspace's expectations.. - Add a comment why plain pin for the global gtt binding is safe at that point. v2: Drop local bind_vm variable (Chris). v3: Explain why this works despite the lack of proper active tracking for the ggtt batch vma. Cc: Chris Wilson Cc: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 48 +++++++++++----------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 70946c551e5d..e1eac15b2583 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -95,7 +95,6 @@ eb_lookup_vmas(struct eb_vmas *eb, struct i915_address_space *vm, struct drm_file *file) { - struct drm_i915_private *dev_priv = vm->dev->dev_private; struct drm_i915_gem_object *obj; struct list_head objects; int i, ret; @@ -130,7 +129,6 @@ eb_lookup_vmas(struct eb_vmas *eb, i = 0; while (!list_empty(&objects)) { struct i915_vma *vma; - struct i915_address_space *bind_vm = vm; if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT && USES_FULL_PPGTT(vm->dev)) { @@ -138,13 +136,6 @@ eb_lookup_vmas(struct eb_vmas *eb, goto err; } - /* If we have secure dispatch, or the userspace assures us that - * they know what they're doing, use the GGTT VM. - */ - if (((args->flags & I915_EXEC_SECURE) && - (i == (args->buffer_count - 1)))) - bind_vm = &dev_priv->gtt.base; - obj = list_first_entry(&objects, struct drm_i915_gem_object, obj_exec_link); @@ -157,7 +148,7 @@ eb_lookup_vmas(struct eb_vmas *eb, * from the (obj, vm) we don't run the risk of creating * duplicated vmas for the same vm. */ - vma = i915_gem_obj_lookup_or_create_vma(obj, bind_vm); + vma = i915_gem_obj_lookup_or_create_vma(obj, vm); if (IS_ERR(vma)) { DRM_DEBUG("Failed to lookup VMA\n"); ret = PTR_ERR(vma); @@ -1391,25 +1382,36 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure * batch" bit. Hence we need to pin secure batches into the global gtt. * hsw should have this fixed, but bdw mucks it up again. */ - if (flags & I915_DISPATCH_SECURE && - !batch_obj->has_global_gtt_mapping) { - /* When we have multiple VMs, we'll need to make sure that we - * allocate space first */ - struct i915_vma *vma = i915_gem_obj_to_ggtt(batch_obj); - BUG_ON(!vma); - vma->bind_vma(vma, batch_obj->cache_level, GLOBAL_BIND); - } + if (flags & I915_DISPATCH_SECURE) { + /* + * So on first glance it looks freaky that we pin the batch here + * outside of the reservation loop. But: + * - The batch is already pinned into the relevant ppgtt, so we + * already have the backing storage fully allocated. + * - No other BO uses the global gtt (well contexts, but meh), + * so we don't really have issues with mutliple objects not + * fitting due to fragmentation. + * So this is actually safe. + */ + ret = i915_gem_obj_ggtt_pin(batch_obj, 0, 0); + if (ret) + goto err; - if (flags & I915_DISPATCH_SECURE) exec_start += i915_gem_obj_ggtt_offset(batch_obj); - else + } else exec_start += i915_gem_obj_offset(batch_obj, vm); ret = legacy_ringbuffer_submission(dev, file, ring, ctx, - args, &eb->vmas, batch_obj, exec_start, flags); - if (ret) - goto err; + args, &eb->vmas, batch_obj, exec_start, flags); + /* + * FIXME: We crucially rely upon the active tracking for the (ppgtt) + * batch vma for correctness. For less ugly and less fragility this + * needs to be adjusted to also track the ggtt batch vma properly as + * active. + */ + if (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 ad19f10bc2a5964f1564639e60953de76b7e50f6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 10 Aug 2014 06:29:08 +0100 Subject: [PATCH 0121/5088] drm/i915: Pre-validate the NEED_GTTS flag for execbuffer We have an implementation requirement that precludes the user from requesting a ggtt entry when the device is operating in ppgtt mode. Move the current check from inside the execbuffer object collation to the prevalidation phase. v2: Roll both invalid flags checks into one Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index e1eac15b2583..446f4b6fbefe 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -130,12 +130,6 @@ eb_lookup_vmas(struct eb_vmas *eb, while (!list_empty(&objects)) { struct i915_vma *vma; - if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT && - USES_FULL_PPGTT(vm->dev)) { - ret = -EINVAL; - goto err; - } - obj = list_first_entry(&objects, struct drm_i915_gem_object, obj_exec_link); @@ -877,18 +871,24 @@ i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) } static int -validate_exec_list(struct drm_i915_gem_exec_object2 *exec, +validate_exec_list(struct drm_device *dev, + struct drm_i915_gem_exec_object2 *exec, int count) { - int i; unsigned relocs_total = 0; unsigned relocs_max = UINT_MAX / sizeof(struct drm_i915_gem_relocation_entry); + unsigned invalid_flags; + int i; + + invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS; + if (USES_FULL_PPGTT(dev)) + invalid_flags |= EXEC_OBJECT_NEEDS_GTT; for (i = 0; i < count; i++) { char __user *ptr = to_user_ptr(exec[i].relocs_ptr); int length; /* limited by fault_in_pages_readable() */ - if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) + if (exec[i].flags & invalid_flags) return -EINVAL; /* First check for malicious input causing overflow in @@ -1250,7 +1250,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (!i915_gem_check_execbuffer(args)) return -EINVAL; - ret = validate_exec_list(exec, args->buffer_count); + ret = validate_exec_list(dev, exec, args->buffer_count); if (ret) return ret; -- GitLab From 060e82c6f4ccf678decffb28ba8301ca9220a995 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 10 Aug 2014 06:29:10 +0100 Subject: [PATCH 0122/5088] drm/i915: Remove redundant list_empty(eb->vmas) tests in execbuffer Part of the pre-validation for an execbuffer call is that there is at least one object in the execlist. As we bail if we fail to lookup any object, we can be sure that after the eb_lookup_vma() there is at least one object in the vma list and so we do not need to assert. Signed-off-by: Chris Wilson Cc: Ben Widawsky Cc: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 446f4b6fbefe..6c07940b468c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -622,9 +622,6 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; int retry; - if (list_empty(vmas)) - return 0; - i915_gem_retire_requests_ring(ring); vm = list_first_entry(vmas, struct i915_vma, exec_list)->vm; @@ -725,9 +722,6 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, int i, total, ret; unsigned count = args->buffer_count; - if (WARN_ON(list_empty(&eb->vmas))) - return 0; - vm = list_first_entry(&eb->vmas, struct i915_vma, exec_list)->vm; /* We may process another execbuffer during the unlock... */ -- GitLab From 906843c3a1acc36407e500a073679c4207d307cd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 10 Aug 2014 06:29:11 +0100 Subject: [PATCH 0123/5088] drm/i915: Simplify relocate_entry_gtt() and make 64-bit safe Even though we should not try to use 4+GiB GTTs on 32-bit systems, by using a local variable we can future proof the code whilst making it easier to read. Signed-off-by: Chris Wilson [danvet: Appease checkpatch a bit.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 25 +++++++++++----------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6c07940b468c..dec2cc2fbd42 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -293,7 +293,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj, struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint64_t delta = reloc->delta + target_offset; - uint32_t __iomem *reloc_entry; + uint64_t offset; void __iomem *reloc_page; int ret; @@ -306,25 +306,24 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj, return ret; /* Map the page containing the relocation we're going to perform. */ - reloc->offset += i915_gem_obj_ggtt_offset(obj); + offset = i915_gem_obj_ggtt_offset(obj); + offset += reloc->offset; reloc_page = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, - reloc->offset & PAGE_MASK); - reloc_entry = (uint32_t __iomem *) - (reloc_page + offset_in_page(reloc->offset)); - iowrite32(lower_32_bits(delta), reloc_entry); + offset & PAGE_MASK); + iowrite32(lower_32_bits(delta), reloc_page + offset_in_page(offset)); if (INTEL_INFO(dev)->gen >= 8) { - reloc_entry += 1; + offset += sizeof(uint32_t); - if (offset_in_page(reloc->offset + sizeof(uint32_t)) == 0) { + if (offset_in_page(offset) == 0) { io_mapping_unmap_atomic(reloc_page); - reloc_page = io_mapping_map_atomic_wc( - dev_priv->gtt.mappable, - reloc->offset + sizeof(uint32_t)); - reloc_entry = reloc_page; + reloc_page = + io_mapping_map_atomic_wc(dev_priv->gtt.mappable, + offset); } - iowrite32(upper_32_bits(delta), reloc_entry); + iowrite32(upper_32_bits(delta), + reloc_page + offset_in_page(offset)); } io_mapping_unmap_atomic(reloc_page); -- GitLab From 2a0d7cfd9482ca4c10a4d8794791760a6a7ce40c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 29 Jul 2014 15:32:37 +0200 Subject: [PATCH 0124/5088] drm: Add a plane->reset hook In general having this can't hurt, and the atomic helpers will need it to be able to reset the state objects properly. The overall idea is to reset in the order pixels flow, so planes -> crtcs -> encoders -> connectors. v2: Squash in fixup from Ville to correctly deference struct drm_plane instead of drm_crtc when walking the plane list. Fixes an oops in driver init and resume. Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 5 +++++ include/drm/drm_crtc.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index cacb460a7145..285e62a134b2 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4663,9 +4663,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, void drm_mode_config_reset(struct drm_device *dev) { struct drm_crtc *crtc; + struct drm_plane *plane; struct drm_encoder *encoder; struct drm_connector *connector; + list_for_each_entry(plane, &dev->mode_config.plane_list, head) + if (plane->funcs->reset) + plane->funcs->reset(plane); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) if (crtc->funcs->reset) crtc->funcs->reset(crtc); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 279565aa0c33..2c1f58d6957a 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -581,6 +581,7 @@ struct drm_plane_funcs { uint32_t src_w, uint32_t src_h); int (*disable_plane)(struct drm_plane *plane); void (*destroy)(struct drm_plane *plane); + void (*reset)(struct drm_plane *plane); int (*set_property)(struct drm_plane *plane, struct drm_property *property, uint64_t val); -- GitLab From e8450f51a4b39cfe0878b4aee339820b2bfff240 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 25 Jul 2014 23:34:03 +0200 Subject: [PATCH 0125/5088] drm/irq: Implement a generic vblank_wait function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As usual in both a crtc index and a struct drm_crtc * version. The function assumes that no one drivers their display below 10Hz, and it will complain if the vblank wait takes longer than that. v2: Also check dev->max_vblank_counter since some drivers register a fake get_vblank_counter function. v3: Use drm_vblank_count instead of calling the low-level ->get_vblank_counter callback. That way we'll get the sw-cooked counter for platforms without proper vblank support and so can ditch the max_vblank_counter check again. v4: Review from Michel Dänzer: - Restore lost notes about v3: - Spelling in kerneldoc. - Inline wait_event condition. - s/vblank_wait/wait_one_vblank/ Cc: Michel Dänzer Cc: Ville Syrjälä Reviewed-by: Michel Dänzer Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 44 +++++++++++++++++++++++++++++++++++++++ include/drm/drmP.h | 2 ++ 2 files changed, 46 insertions(+) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 6f16a104d6d0..e64d24951fc2 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1009,6 +1009,50 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_vblank_put); +/** + * drm_wait_one_vblank - wait for one vblank + * @dev: DRM device + * @crtc: crtc index + * + * This waits for one vblank to pass on @crtc, using the irq driver interfaces. + * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. + * due to lack of driver support or because the crtc is off. + */ +void drm_wait_one_vblank(struct drm_device *dev, int crtc) +{ + int ret; + u32 last; + + ret = drm_vblank_get(dev, crtc); + if (WARN_ON(ret)) + return; + + last = drm_vblank_count(dev, crtc); + + ret = wait_event_timeout(dev->vblank[crtc].queue, + last != drm_vblank_count(dev, crtc), + msecs_to_jiffies(100)); + + WARN_ON(ret == 0); + + drm_vblank_put(dev, crtc); +} +EXPORT_SYMBOL(drm_wait_one_vblank); + +/** + * drm_crtc_wait_one_vblank - wait for one vblank + * @crtc: DRM crtc + * + * This waits for one vblank to pass on @crtc, using the irq driver interfaces. + * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. + * due to lack of driver support or because the crtc is off. + */ +void drm_crtc_wait_one_vblank(struct drm_crtc *crtc) +{ + drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_wait_one_vblank); + /** * drm_vblank_off - disable vblank events on a CRTC * @dev: DRM device diff --git a/include/drm/drmP.h b/include/drm/drmP.h index d3d9be6b83ef..c2209178981f 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1327,6 +1327,8 @@ extern int drm_vblank_get(struct drm_device *dev, int crtc); extern void drm_vblank_put(struct drm_device *dev, int crtc); extern int drm_crtc_vblank_get(struct drm_crtc *crtc); extern void drm_crtc_vblank_put(struct drm_crtc *crtc); +extern void drm_wait_one_vblank(struct drm_device *dev, int crtc); +extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc); extern void drm_vblank_off(struct drm_device *dev, int crtc); extern void drm_vblank_on(struct drm_device *dev, int crtc); extern void drm_crtc_vblank_off(struct drm_crtc *crtc); -- GitLab From b20385f1f8434ec32d73414ffcadb7dcbd3a2a61 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:10 +0100 Subject: [PATCH 0126/5088] drm/i915/bdw: New source and header file for LRs, LRCs and Execlists Some legacy HW context code assumptions don't make sense for this new submission method, so we will place this stuff in a separate file. Note for reviewers: I've carefully considered the best name for this file and this was my best option (other possibilities were intel_lr_context.c or intel_execlist.c). I am open to a certain bikeshedding on this matter, anyway. And some point in time, it would be a good idea to split intel_lrc.c/.h even further, but for the moment just shove everything together. v2: Change to intel_lrc.c v3: Squash together with the header file addition Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_lrc.c | 42 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_lrc.h | 27 ++++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 drivers/gpu/drm/i915/intel_lrc.c create mode 100644 drivers/gpu/drm/i915/intel_lrc.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 91bd167e1cb7..c1dd485aeb6c 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -31,6 +31,7 @@ i915-y += i915_cmd_parser.o \ i915_gpu_error.o \ i915_irq.o \ i915_trace_points.o \ + intel_lrc.o \ intel_ringbuffer.o \ intel_uncore.o diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6959c1b2d648..ec2a094f3622 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -35,6 +35,7 @@ #include "i915_reg.h" #include "intel_bios.h" #include "intel_ringbuffer.h" +#include "intel_lrc.h" #include "i915_gem_gtt.h" #include #include diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c new file mode 100644 index 000000000000..49bb6fcdface --- /dev/null +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -0,0 +1,42 @@ +/* + * 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. + * + * Authors: + * Ben Widawsky + * Michel Thierry + * Thomas Daniel + * Oscar Mateo + * + */ + +/* + * GEN8 brings an expansion of the HW contexts: "Logical Ring Contexts". + * These expanded contexts enable a number of new abilities, especially + * "Execlists" (also implemented in this file). + * + * Execlists are the new method by which, on gen8+ hardware, workloads are + * submitted for execution (as opposed to the legacy, ringbuffer-based, method). + */ + +#include +#include +#include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h new file mode 100644 index 000000000000..f6830a4ec773 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -0,0 +1,27 @@ +/* + * 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_LRC_H_ +#define _INTEL_LRC_H_ + +#endif /* _INTEL_LRC_H_ */ -- GitLab From 127f100369a1f302904335950387d566680eb275 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:11 +0100 Subject: [PATCH 0127/5088] drm/i915/bdw: Macro for LRCs and module option for Execlists GEN8 brings an expansion of the HW contexts: "Logical Ring Contexts". These expanded contexts enable a number of new abilities, especially "Execlists". The macro is defined to off until we have things in place to hope to work. v2: Rename "advanced contexts" to the more correct "logical ring contexts". v3: Add a module parameter to enable execlists. Execlist are relatively new, and so it'd be wise to be able to switch back to ring submission to debug subtle problems that will inevitably arise. v4: Add an intel_enable_execlists function. v5: Sanitize early, as suggested by Daniel. Remove lrc_enabled. Signed-off-by: Ben Widawsky (v1) Signed-off-by: Damien Lespiau (v3) Signed-off-by: Oscar Mateo (v2, v4 & v5) Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem.c | 3 +++ drivers/gpu/drm/i915/i915_params.c | 6 ++++++ drivers/gpu/drm/i915/intel_lrc.c | 11 +++++++++++ drivers/gpu/drm/i915/intel_lrc.h | 3 +++ 5 files changed, 25 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ec2a094f3622..fd2aa15ce02b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2062,6 +2062,7 @@ struct drm_i915_cmd_table { #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) #define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 6) +#define HAS_LOGICAL_RING_CONTEXTS(dev) 0 #define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_PPGTT(dev) (INTEL_INFO(dev)->gen >= 7 && !IS_GEN8(dev)) #define USES_PPGTT(dev) (i915.enable_ppgtt) @@ -2149,6 +2150,7 @@ struct i915_params { int enable_rc6; int enable_fbc; int enable_ppgtt; + int enable_execlists; int enable_psr; unsigned int preliminary_hw_support; int disable_power_well; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3eec344bdac0..5646e9ba6383 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4723,6 +4723,9 @@ int i915_gem_init(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + i915.enable_execlists = intel_sanitize_enable_execlists(dev, + i915.enable_execlists); + mutex_lock(&dev->struct_mutex); if (IS_VALLEYVIEW(dev)) { diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 62ee8308d682..f7f8350c3793 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -35,6 +35,7 @@ struct i915_params i915 __read_mostly = { .vbt_sdvo_panel_type = -1, .enable_rc6 = -1, .enable_fbc = -1, + .enable_execlists = -1, .enable_hangcheck = true, .enable_ppgtt = -1, .enable_psr = 1, @@ -118,6 +119,11 @@ MODULE_PARM_DESC(enable_ppgtt, "Override PPGTT usage. " "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)"); +module_param_named(enable_execlists, i915.enable_execlists, int, 0400); +MODULE_PARM_DESC(enable_execlists, + "Override execlists usage. " + "(-1=auto [default], 0=disabled, 1=enabled)"); + module_param_named(enable_psr, i915.enable_psr, int, 0600); MODULE_PARM_DESC(enable_psr, "Enable PSR (default: true)"); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 49bb6fcdface..21f7f1cce86e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -40,3 +40,14 @@ #include #include #include "i915_drv.h" + +int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists) +{ + if (enable_execlists == 0) + return 0; + + if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev)) + return 1; + + return 0; +} diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index f6830a4ec773..75ee9c3cb7dc 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -24,4 +24,7 @@ #ifndef _INTEL_LRC_H_ #define _INTEL_LRC_H_ +/* Execlists */ +int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists); + #endif /* _INTEL_LRC_H_ */ -- GitLab From bd84b1e995918ad83bdba5d5be1bef901e169f19 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 11 Aug 2014 15:57:57 +0200 Subject: [PATCH 0128/5088] drm/i915: WARN if module opt sanitization goes out of order Depending upon one module option to be sanitized (through USES_PPGTT) for the other is a bit too fragile for my taste. At least WARN about this. Cc: Ben Widawsky Cc: Damien Lespiau Cc: Oscar Mateo Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 21f7f1cce86e..44721292eb77 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -43,6 +43,8 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists) { + WARN_ON(i915.enable_ppgtt == -1); + if (enable_execlists == 0) return 0; -- GitLab From ede7d42baeece583c864badb6f9081f4cded6c32 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:12 +0100 Subject: [PATCH 0129/5088] drm/i915/bdw: Initialization for Logical Ring Contexts For the moment this is just a placeholder, but it shows one of the main differences between the good ol' HW contexts and the shiny new Logical Ring Contexts: LR contexts allocate and free their own backing objects. Another difference is that the allocation is deferred (as the create function name suggests), but that does not happen in this patch yet, because for the moment we are only dealing with the default context. Early in the series we had our own gen8_gem_context_init/fini functions, but the truth is they now look almost the same as the legacy hw context init/fini functions. We can always split them later if this ceases to be the case. Also, we do not fall back to legacy ringbuffers when logical ring context initialization fails (not very likely to happen and, even if it does, hw contexts would probably fail as well). v2: Daniel says "explain, do not showcase". Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: s/BUG_ON/WARN_ON/.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 29 ++++++++++++++++++++----- drivers/gpu/drm/i915/intel_lrc.c | 15 +++++++++++++ drivers/gpu/drm/i915/intel_lrc.h | 5 +++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 3b99390e467a..3552a351ccf7 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -182,7 +182,10 @@ void i915_gem_context_free(struct kref *ctx_ref) typeof(*ctx), ref); struct i915_hw_ppgtt *ppgtt = NULL; - if (ctx->legacy_hw_ctx.rcs_state) { + if (i915.enable_execlists) { + ppgtt = ctx_to_ppgtt(ctx); + intel_lr_context_free(ctx); + } else if (ctx->legacy_hw_ctx.rcs_state) { /* We refcount even the aliasing PPGTT to keep the code symmetric */ if (USES_PPGTT(ctx->legacy_hw_ctx.rcs_state->base.dev)) ppgtt = ctx_to_ppgtt(ctx); @@ -417,7 +420,11 @@ int i915_gem_context_init(struct drm_device *dev) if (WARN_ON(dev_priv->ring[RCS].default_context)) return 0; - if (HAS_HW_CONTEXTS(dev)) { + if (i915.enable_execlists) { + /* NB: intentionally left blank. We will allocate our own + * backing objects as we need them, thank you very much */ + dev_priv->hw_context_size = 0; + } else if (HAS_HW_CONTEXTS(dev)) { dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); if (dev_priv->hw_context_size > (1<<20)) { DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n", @@ -433,11 +440,20 @@ int i915_gem_context_init(struct drm_device *dev) return PTR_ERR(ctx); } - /* NB: RCS will hold a ref for all rings */ - for (i = 0; i < I915_NUM_RINGS; i++) - dev_priv->ring[i].default_context = ctx; + for (i = 0; i < I915_NUM_RINGS; i++) { + struct intel_engine_cs *ring = &dev_priv->ring[i]; + + /* NB: RCS will hold a ref for all rings */ + ring->default_context = ctx; + + /* FIXME: we really only want to do this for initialized rings */ + if (i915.enable_execlists) + intel_lr_context_deferred_create(ctx, ring); + } - DRM_DEBUG_DRIVER("%s context support initialized\n", dev_priv->hw_context_size ? "HW" : "fake"); + DRM_DEBUG_DRIVER("%s context support initialized\n", + i915.enable_execlists ? "LR" : + dev_priv->hw_context_size ? "HW" : "fake"); return 0; } @@ -779,6 +795,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct intel_context *ctx; int ret; + /* FIXME: allow user-created LR contexts as well */ if (!hw_context_enabled(dev)) return -ENODEV; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 44721292eb77..2d82d52d18bb 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -53,3 +53,18 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists return 0; } + +void intel_lr_context_free(struct intel_context *ctx) +{ + /* TODO */ +} + +int intel_lr_context_deferred_create(struct intel_context *ctx, + struct intel_engine_cs *ring) +{ + WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL); + + /* TODO */ + + return 0; +} diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 75ee9c3cb7dc..3b93572431e3 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -24,6 +24,11 @@ #ifndef _INTEL_LRC_H_ #define _INTEL_LRC_H_ +/* Logical Ring Contexts */ +void intel_lr_context_free(struct intel_context *ctx); +int intel_lr_context_deferred_create(struct intel_context *ctx, + struct intel_engine_cs *ring); + /* Execlists */ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists); -- GitLab From c9e003af2d44d9f6eafe855448c41c9ac08ae895 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:13 +0100 Subject: [PATCH 0130/5088] drm/i915/bdw: Introduce one context backing object per engine A context backing object only makes sense for a given engine (because it holds state data specific to that engine). In legacy ringbuffer sumission mode, the only MI_SET_CONTEXT we really perform is for the render engine, so one backing object is all we nee. With Execlists, however, we need backing objects for every engine, as contexts become the only way to submit workloads to the GPU. To tackle this problem, we multiplex the context struct to contain objects. Originally, I colored this code by instantiating one new context for every engine I wanted to use, but this change suggested by Brad Volkin makes it more elegant. v2: Leave the old backing object pointer behind. Daniel Vetter suggested using a union, but it makes more sense to keep rcs_state as a NULL pointer behind, to make sure no one uses it incorrectly when Execlists are enabled, similar to what he suggested for ring->buffer (Rusty's API level 5). v3: Use the name "state" instead of the too-generic "obj", so that it mirrors the name choice for the legacy rcs_state. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fd2aa15ce02b..ad70e8ec18bc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -626,11 +626,17 @@ struct intel_context { struct i915_ctx_hang_stats hang_stats; struct i915_address_space *vm; + /* Legacy ring buffer submission */ struct { struct drm_i915_gem_object *rcs_state; bool initialized; } legacy_hw_ctx; + /* Execlists */ + struct { + struct drm_i915_gem_object *state; + } engine[I915_NUM_RINGS]; + struct list_head link; }; -- GitLab From 8c8579176a144b1dca1d99ebb92510924168d508 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:14 +0100 Subject: [PATCH 0131/5088] drm/i915/bdw: A bit more advanced LR context alloc/free Now that we have the ability to allocate our own context backing objects and we have multiplexed one of them per engine inside the context structs, we can finally allocate and free them correctly. Regarding the context size, reading the register to calculate the sizes can work, I think, however the docs are very clear about the actual context sizes on GEN8, so just hardcode that and use it. v2: Rebased on top of the Full PPGTT series. It is important to notice that at this point we have one global default context per engine, all of them using the aliasing PPGTT (as opposed to the single global default context we have with legacy HW contexts). v3: - Go back to one single global default context, this time with multiple backing objects inside. - Use different context sizes for non-render engines, as suggested by Damien (still hardcoded, since the information about the context size registers in the BSpec is, well, *lacking*). - Render ctx size is 20 (or 19) pages, but not 21 (caught by Damien). - Move default context backing object creation to intel_init_ring (so that we don't waste memory in rings that might not get initialized). v4: - Reuse the HW legacy context init/fini. - Create a separate free function. - Rename the functions with an intel_ preffix. v5: Several rebases to account for the changes in the previous patches. Signed-off-by: Ben Widawsky (v1) Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 59 ++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ad70e8ec18bc..cbae19bab4bf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2528,6 +2528,8 @@ int i915_switch_context(struct intel_engine_cs *ring, 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); +struct drm_i915_gem_object * +i915_gem_alloc_context_obj(struct drm_device *dev, size_t size); static inline void i915_gem_context_reference(struct intel_context *ctx) { kref_get(&ctx->ref); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 3552a351ccf7..9f8fbbacf6c0 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -199,7 +199,7 @@ void i915_gem_context_free(struct kref *ctx_ref) kfree(ctx); } -static struct drm_i915_gem_object * +struct drm_i915_gem_object * i915_gem_alloc_context_obj(struct drm_device *dev, size_t size) { struct drm_i915_gem_object *obj; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 2d82d52d18bb..9f30ee80e487 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -41,6 +41,11 @@ #include #include "i915_drv.h" +#define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE) +#define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE) + +#define GEN8_LR_CONTEXT_ALIGN 4096 + int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists) { WARN_ON(i915.enable_ppgtt == -1); @@ -56,15 +61,65 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists void intel_lr_context_free(struct intel_context *ctx) { - /* TODO */ + int i; + + for (i = 0; i < I915_NUM_RINGS; i++) { + struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state; + if (ctx_obj) { + i915_gem_object_ggtt_unpin(ctx_obj); + drm_gem_object_unreference(&ctx_obj->base); + } + } +} + +static uint32_t get_lr_context_size(struct intel_engine_cs *ring) +{ + int ret = 0; + + WARN_ON(INTEL_INFO(ring->dev)->gen != 8); + + switch (ring->id) { + case RCS: + ret = GEN8_LR_CONTEXT_RENDER_SIZE; + break; + case VCS: + case BCS: + case VECS: + case VCS2: + ret = GEN8_LR_CONTEXT_OTHER_SIZE; + break; + } + + return ret; } int intel_lr_context_deferred_create(struct intel_context *ctx, struct intel_engine_cs *ring) { + struct drm_device *dev = ring->dev; + struct drm_i915_gem_object *ctx_obj; + uint32_t context_size; + int ret; + WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL); - /* TODO */ + context_size = round_up(get_lr_context_size(ring), 4096); + + ctx_obj = i915_gem_alloc_context_obj(dev, context_size); + if (IS_ERR(ctx_obj)) { + ret = PTR_ERR(ctx_obj); + DRM_DEBUG_DRIVER("Alloc LRC backing obj failed: %d\n", ret); + return ret; + } + + ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0); + if (ret) { + DRM_DEBUG_DRIVER("Pin LRC backing obj failed: %d\n", ret); + drm_gem_object_unreference(&ctx_obj->base); + return ret; + } + + ctx->engine[ring->id].state = ctx_obj; return 0; } -- GitLab From 84c2377fcee7a43cd964b62143e9a3714130bb0c Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:15 +0100 Subject: [PATCH 0132/5088] drm/i915/bdw: Allocate ringbuffers for Logical Ring Contexts As we have said a couple of times by now, logical ring contexts have their own ringbuffers: not only the backing pages, but the whole management struct. In a previous version of the series, this was achieved with two separate patches: drm/i915/bdw: Allocate ringbuffer backing objects for default global LRC drm/i915/bdw: Allocate ringbuffer for user-created LRCs Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_lrc.c | 38 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 6 ++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cbae19bab4bf..eccb8e406e9c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -635,6 +635,7 @@ struct intel_context { /* Execlists */ struct { struct drm_i915_gem_object *state; + struct intel_ringbuffer *ringbuf; } engine[I915_NUM_RINGS]; struct list_head link; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9f30ee80e487..0c80bb1f5420 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -65,7 +65,11 @@ void intel_lr_context_free(struct intel_context *ctx) for (i = 0; i < I915_NUM_RINGS; i++) { struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state; + struct intel_ringbuffer *ringbuf = ctx->engine[i].ringbuf; + if (ctx_obj) { + intel_destroy_ringbuffer_obj(ringbuf); + kfree(ringbuf); i915_gem_object_ggtt_unpin(ctx_obj); drm_gem_object_unreference(&ctx_obj->base); } @@ -99,6 +103,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, struct drm_device *dev = ring->dev; struct drm_i915_gem_object *ctx_obj; uint32_t context_size; + struct intel_ringbuffer *ringbuf; int ret; WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL); @@ -119,6 +124,39 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, return ret; } + ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL); + if (!ringbuf) { + DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n", + ring->name); + i915_gem_object_ggtt_unpin(ctx_obj); + drm_gem_object_unreference(&ctx_obj->base); + ret = -ENOMEM; + return ret; + } + + ringbuf->size = 32 * PAGE_SIZE; + ringbuf->effective_size = ringbuf->size; + ringbuf->head = 0; + ringbuf->tail = 0; + ringbuf->space = ringbuf->size; + ringbuf->last_retired_head = -1; + + /* TODO: For now we put this in the mappable region so that we can reuse + * the existing ringbuffer code which ioremaps it. When we start + * creating many contexts, this will no longer work and we must switch + * to a kmapish interface. + */ + ret = intel_alloc_ringbuffer_obj(dev, ringbuf); + if (ret) { + DRM_DEBUG_DRIVER("Failed to allocate ringbuffer obj %s: %d\n", + ring->name, ret); + kfree(ringbuf); + i915_gem_object_ggtt_unpin(ctx_obj); + drm_gem_object_unreference(&ctx_obj->base); + return ret; + } + + ctx->engine[ring->id].ringbuf = ringbuf; ctx->engine[ring->id].state = ctx_obj; return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a059b64a0fb2..064652034d7e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1519,7 +1519,7 @@ static int init_phys_status_page(struct intel_engine_cs *ring) return 0; } -static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf) +void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf) { if (!ringbuf->obj) return; @@ -1530,8 +1530,8 @@ static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf) ringbuf->obj = NULL; } -static int intel_alloc_ringbuffer_obj(struct drm_device *dev, - struct intel_ringbuffer *ringbuf) +int intel_alloc_ringbuffer_obj(struct drm_device *dev, + struct intel_ringbuffer *ringbuf) { struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_gem_object *obj; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 70525d0c2c74..669cc7527f9a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -355,6 +355,10 @@ intel_write_status_page(struct intel_engine_cs *ring, #define I915_GEM_HWS_SCRATCH_INDEX 0x30 #define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT) +void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf); +int intel_alloc_ringbuffer_obj(struct drm_device *dev, + struct intel_ringbuffer *ringbuf); + void intel_stop_ring_buffer(struct intel_engine_cs *ring); void intel_cleanup_ring_buffer(struct intel_engine_cs *ring); -- GitLab From 0c7dd53b84def4fbbba907bef3d32a5171b617a5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 11 Aug 2014 16:17:44 +0200 Subject: [PATCH 0133/5088] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer Any given ringbuffer is unequivocally tied to one context and one engine. By setting the appropriate pointers to them, the ringbuffer struct holds all the infromation you might need to submit a workload for processing, Execlists style. v2: Drop ring->ctx since that looks terribly ill-defined for legacy ringbuffer submission. Signed-off-by: Oscar Mateo (v1) Acked-by: Damien Lespiau (v2) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 1 + drivers/gpu/drm/i915/intel_ringbuffer.h | 2 ++ 3 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 0c80bb1f5420..8f2d14da6228 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -134,6 +134,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, return ret; } + ringbuf->ring = ring; ringbuf->size = 32 * PAGE_SIZE; ringbuf->effective_size = ringbuf->size; ringbuf->head = 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 064652034d7e..c35f956ed6a0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1594,6 +1594,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); ringbuf->size = 32 * PAGE_SIZE; + ringbuf->ring = ring; memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno)); init_waitqueue_head(&ring->irq_queue); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 669cc7527f9a..fe9d9d9d3598 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -90,6 +90,8 @@ struct intel_ringbuffer { struct drm_i915_gem_object *obj; void __iomem *virtual_start; + struct intel_engine_cs *ring; + u32 head; u32 tail; int space; -- GitLab From 8670d6f97d8c19595950af1838f8458d7529825f Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:17 +0100 Subject: [PATCH 0134/5088] drm/i915/bdw: Populate LR contexts (somewhat) For the most part, logical ring context objects are similar to hardware contexts in that the backing object is meant to be opaque. There are some exceptions where we need to poke certain offsets of the object for initialization, updating the tail pointer or updating the PDPs. For our basic execlist implementation we'll only need our PPGTT PDs, and ringbuffer addresses in order to set up the context. With previous patches, we have both, so start prepping the context to be load. Before running a context for the first time you must populate some fields in the context object. These fields begin 1 PAGE + LRCA, ie. the first page (in 0 based counting) of the context image. These same fields will be read and written to as contexts are saved and restored once the system is up and running. Many of these fields are completely reused from previous global registers: ringbuffer head/tail/control, context control matches some previous MI_SET_CONTEXT flags, and page directories. There are other fields which we don't touch which we may want in the future. v2: CTX_LRI_HEADER_0 is MI_LOAD_REGISTER_IMM(14) for render and (11) for other engines. v3: Several rebases and general changes to the code. v4: Squash with "Extract LR context object populating" Also, Damien's review comments: - Set the Force Posted bit on the LRI header, as the BSpec suggest we do. - Prevent warning when compiling a 32-bits kernel without HIGHMEM64. - Add a clarifying comment to the context population code. v5: Damien's review comments: - The third MI_LOAD_REGISTER_IMM in the context does not set Force Posted. - Remove dead code. v6: Add a note about the (presumed) differences between BDW and CHV state contexts. Also, Brad's review comments: - Use the _MASKED_BIT_ENABLE, upper_32_bits and lower_32_bits macros. - Be less magical about how we set the ring size in the context. Signed-off-by: Ben Widawsky (v1) Signed-off-by: Rafael Barbalho (v2) Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_lrc.c | 159 ++++++++++++++++++++++++++++++- 2 files changed, 156 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7a6cc69cdc2b..c1d24242a02d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -282,6 +282,7 @@ * address/value pairs. Don't overdue it, though, x <= 2^4 must hold! */ #define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*(x)-1) +#define MI_LRI_FORCE_POSTED (1<<12) #define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*(x)-1) #define MI_STORE_REGISTER_MEM_GEN8(x) MI_INSTR(0x24, 3*(x)-1) #define MI_SRM_LRM_GLOBAL_GTT (1<<22) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8f2d14da6228..a7a08a85edb3 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -46,6 +46,38 @@ #define GEN8_LR_CONTEXT_ALIGN 4096 +#define RING_ELSP(ring) ((ring)->mmio_base+0x230) +#define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244) + +#define CTX_LRI_HEADER_0 0x01 +#define CTX_CONTEXT_CONTROL 0x02 +#define CTX_RING_HEAD 0x04 +#define CTX_RING_TAIL 0x06 +#define CTX_RING_BUFFER_START 0x08 +#define CTX_RING_BUFFER_CONTROL 0x0a +#define CTX_BB_HEAD_U 0x0c +#define CTX_BB_HEAD_L 0x0e +#define CTX_BB_STATE 0x10 +#define CTX_SECOND_BB_HEAD_U 0x12 +#define CTX_SECOND_BB_HEAD_L 0x14 +#define CTX_SECOND_BB_STATE 0x16 +#define CTX_BB_PER_CTX_PTR 0x18 +#define CTX_RCS_INDIRECT_CTX 0x1a +#define CTX_RCS_INDIRECT_CTX_OFFSET 0x1c +#define CTX_LRI_HEADER_1 0x21 +#define CTX_CTX_TIMESTAMP 0x22 +#define CTX_PDP3_UDW 0x24 +#define CTX_PDP3_LDW 0x26 +#define CTX_PDP2_UDW 0x28 +#define CTX_PDP2_LDW 0x2a +#define CTX_PDP1_UDW 0x2c +#define CTX_PDP1_LDW 0x2e +#define CTX_PDP0_UDW 0x30 +#define CTX_PDP0_LDW 0x32 +#define CTX_LRI_HEADER_2 0x41 +#define CTX_R_PWR_CLK_STATE 0x42 +#define CTX_GPGPU_CSR_BASE_ADDRESS 0x44 + int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists) { WARN_ON(i915.enable_ppgtt == -1); @@ -59,6 +91,115 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists return 0; } +static int +populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_obj, + struct intel_engine_cs *ring, struct intel_ringbuffer *ringbuf) +{ + struct drm_i915_gem_object *ring_obj = ringbuf->obj; + struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(ctx); + struct page *page; + uint32_t *reg_state; + int ret; + + ret = i915_gem_object_set_to_cpu_domain(ctx_obj, true); + if (ret) { + DRM_DEBUG_DRIVER("Could not set to CPU domain\n"); + return ret; + } + + ret = i915_gem_object_get_pages(ctx_obj); + if (ret) { + DRM_DEBUG_DRIVER("Could not get object pages\n"); + return ret; + } + + i915_gem_object_pin_pages(ctx_obj); + + /* The second page of the context object contains some fields which must + * be set up prior to the first execution. */ + page = i915_gem_object_get_page(ctx_obj, 1); + reg_state = kmap_atomic(page); + + /* A context is actually a big batch buffer with several MI_LOAD_REGISTER_IMM + * commands followed by (reg, value) pairs. The values we are setting here are + * only for the first context restore: on a subsequent save, the GPU will + * recreate this batchbuffer with new values (including all the missing + * MI_LOAD_REGISTER_IMM commands that we are not initializing here). */ + if (ring->id == RCS) + reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(14); + else + reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(11); + reg_state[CTX_LRI_HEADER_0] |= MI_LRI_FORCE_POSTED; + reg_state[CTX_CONTEXT_CONTROL] = RING_CONTEXT_CONTROL(ring); + reg_state[CTX_CONTEXT_CONTROL+1] = + _MASKED_BIT_ENABLE((1<<3) | MI_RESTORE_INHIBIT); + 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); + reg_state[CTX_RING_TAIL+1] = 0; + reg_state[CTX_RING_BUFFER_START] = RING_START(ring->mmio_base); + reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(ring_obj); + reg_state[CTX_RING_BUFFER_CONTROL] = RING_CTL(ring->mmio_base); + reg_state[CTX_RING_BUFFER_CONTROL+1] = + ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID; + reg_state[CTX_BB_HEAD_U] = ring->mmio_base + 0x168; + reg_state[CTX_BB_HEAD_U+1] = 0; + reg_state[CTX_BB_HEAD_L] = ring->mmio_base + 0x140; + reg_state[CTX_BB_HEAD_L+1] = 0; + reg_state[CTX_BB_STATE] = ring->mmio_base + 0x110; + reg_state[CTX_BB_STATE+1] = (1<<5); + reg_state[CTX_SECOND_BB_HEAD_U] = ring->mmio_base + 0x11c; + reg_state[CTX_SECOND_BB_HEAD_U+1] = 0; + reg_state[CTX_SECOND_BB_HEAD_L] = ring->mmio_base + 0x114; + reg_state[CTX_SECOND_BB_HEAD_L+1] = 0; + 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; + } + reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9); + reg_state[CTX_LRI_HEADER_1] |= MI_LRI_FORCE_POSTED; + reg_state[CTX_CTX_TIMESTAMP] = ring->mmio_base + 0x3a8; + reg_state[CTX_CTX_TIMESTAMP+1] = 0; + reg_state[CTX_PDP3_UDW] = GEN8_RING_PDP_UDW(ring, 3); + reg_state[CTX_PDP3_LDW] = GEN8_RING_PDP_LDW(ring, 3); + reg_state[CTX_PDP2_UDW] = GEN8_RING_PDP_UDW(ring, 2); + reg_state[CTX_PDP2_LDW] = GEN8_RING_PDP_LDW(ring, 2); + reg_state[CTX_PDP1_UDW] = GEN8_RING_PDP_UDW(ring, 1); + reg_state[CTX_PDP1_LDW] = GEN8_RING_PDP_LDW(ring, 1); + reg_state[CTX_PDP0_UDW] = GEN8_RING_PDP_UDW(ring, 0); + reg_state[CTX_PDP0_LDW] = GEN8_RING_PDP_LDW(ring, 0); + reg_state[CTX_PDP3_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[3]); + reg_state[CTX_PDP3_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[3]); + reg_state[CTX_PDP2_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[2]); + reg_state[CTX_PDP2_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[2]); + reg_state[CTX_PDP1_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[1]); + reg_state[CTX_PDP1_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[1]); + reg_state[CTX_PDP0_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[0]); + reg_state[CTX_PDP0_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[0]); + if (ring->id == RCS) { + reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1); + reg_state[CTX_R_PWR_CLK_STATE] = 0x20c8; + reg_state[CTX_R_PWR_CLK_STATE+1] = 0; + } + + kunmap_atomic(reg_state); + + ctx_obj->dirty = 1; + set_page_dirty(page); + i915_gem_object_unpin_pages(ctx_obj); + + return 0; +} + void intel_lr_context_free(struct intel_context *ctx) { int i; @@ -151,14 +292,24 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, if (ret) { DRM_DEBUG_DRIVER("Failed to allocate ringbuffer obj %s: %d\n", ring->name, ret); - kfree(ringbuf); - i915_gem_object_ggtt_unpin(ctx_obj); - drm_gem_object_unreference(&ctx_obj->base); - return ret; + goto error; + } + + ret = populate_lr_context(ctx, ctx_obj, ring, ringbuf); + if (ret) { + DRM_DEBUG_DRIVER("Failed to populate LRC: %d\n", ret); + intel_destroy_ringbuffer_obj(ringbuf); + goto error; } ctx->engine[ring->id].ringbuf = ringbuf; ctx->engine[ring->id].state = ctx_obj; return 0; + +error: + kfree(ringbuf); + i915_gem_object_ggtt_unpin(ctx_obj); + drm_gem_object_unreference(&ctx_obj->base); + return ret; } -- GitLab From ec3e9963a681789860e5c0120a745b717d942392 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:18 +0100 Subject: [PATCH 0135/5088] drm/i915/bdw: Deferred creation of user-created LRCs The backing objects and ringbuffers for contexts created via open fd are actually empty until the user starts sending execbuffers to them. At that point, we allocate & populate them. We do this because, at create time, we really don't know which engine is going to be used with the context later on (and we don't want to waste memory on objects that we might never use). v2: As contexts created via ioctl can only be used with the render ring, we have enough information to allocate & populate them right away. v3: Defer the creation always, even with ioctl-created contexts, as requested by Daniel Vetter. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 7 +++---- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 8 ++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 9f8fbbacf6c0..bcb41002aa13 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -782,9 +782,9 @@ int i915_switch_context(struct intel_engine_cs *ring, return do_switch(ring, to); } -static bool hw_context_enabled(struct drm_device *dev) +static bool contexts_enabled(struct drm_device *dev) { - return to_i915(dev)->hw_context_size; + return i915.enable_execlists || to_i915(dev)->hw_context_size; } int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, @@ -795,8 +795,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct intel_context *ctx; int ret; - /* FIXME: allow user-created LR contexts as well */ - if (!hw_context_enabled(dev)) + if (!contexts_enabled(dev)) return -ENODEV; ret = i915_mutex_lock_interruptible(dev); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index dec2cc2fbd42..29cb2156d32b 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -931,6 +931,14 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, return ERR_PTR(-EIO); } + if (i915.enable_execlists && !ctx->engine[ring->id].state) { + int ret = intel_lr_context_deferred_create(ctx, ring); + if (ret) { + DRM_DEBUG("Could not create LRC %u: %d\n", ctx_id, ret); + return ERR_PTR(ret); + } + } + return ctx; } -- GitLab From a83014d3f8b936778a9bc9b3d4137769bb26d9eb Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:21 +0100 Subject: [PATCH 0136/5088] drm/i915: Abstract the legacy workload submission mechanism away As suggested by Daniel Vetter. The idea, in subsequent patches, is to provide an alternative to these vfuncs for the Execlists submission mechanism. v2: Splitted into two and reordered to illustrate our intentions, instead of showing it off. Also, remove the add_request vfunc and added the stop_ring one. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: - Make checkpatch happy. - Be grumpy about the excessive vtable. - Ditch gt->is_ring_initialized.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 23 ++++++++++++++++++++++ drivers/gpu/drm/i915/i915_gem.c | 15 ++++++++++---- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 20 +++++++++---------- 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index eccb8e406e9c..9198f1c96470 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1645,6 +1645,20 @@ struct drm_i915_private { /* Old ums support infrastructure, same warning applies. */ struct i915_ums_state ums; + /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */ + struct { + int (*do_execbuf)(struct drm_device *dev, struct drm_file *file, + struct intel_engine_cs *ring, + struct intel_context *ctx, + struct drm_i915_gem_execbuffer2 *args, + struct list_head *vmas, + struct drm_i915_gem_object *batch_obj, + u64 exec_start, u32 flags); + int (*init_rings)(struct drm_device *dev); + void (*cleanup_ring)(struct intel_engine_cs *ring); + void (*stop_ring)(struct intel_engine_cs *ring); + } gt; + /* * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * will be rejected. Instead look for a better place. @@ -2252,6 +2266,14 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int i915_gem_ringbuffer_submission(struct drm_device *dev, + struct drm_file *file, + struct intel_engine_cs *ring, + struct intel_context *ctx, + struct drm_i915_gem_execbuffer2 *args, + struct list_head *vmas, + struct drm_i915_gem_object *batch_obj, + u64 exec_start, u32 flags); 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, @@ -2404,6 +2426,7 @@ void i915_gem_reset(struct drm_device *dev); bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force); int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj); 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); void i915_gem_init_swizzling(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5646e9ba6383..33a54cbf9a2e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4495,7 +4495,7 @@ i915_gem_stop_ringbuffers(struct drm_device *dev) int i; for_each_ring(ring, dev_priv, i) - intel_stop_ring_buffer(ring); + dev_priv->gt.stop_ring(ring); } int @@ -4612,7 +4612,7 @@ intel_enable_blt(struct drm_device *dev) return true; } -static int i915_gem_init_rings(struct drm_device *dev) +int i915_gem_init_rings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int ret; @@ -4695,7 +4695,7 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_init_swizzling(dev); - ret = i915_gem_init_rings(dev); + ret = dev_priv->gt.init_rings(dev); if (ret) return ret; @@ -4736,6 +4736,13 @@ int i915_gem_init(struct drm_device *dev) DRM_DEBUG_DRIVER("allow wake ack timed out\n"); } + if (!i915.enable_execlists) { + dev_priv->gt.do_execbuf = i915_gem_ringbuffer_submission; + dev_priv->gt.init_rings = i915_gem_init_rings; + dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer; + dev_priv->gt.stop_ring = intel_stop_ring_buffer; + } + i915_gem_init_userptr(dev); i915_gem_init_global_gtt(dev); @@ -4771,7 +4778,7 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) int i; for_each_ring(ring, dev_priv, i) - intel_cleanup_ring_buffer(ring); + dev_priv->gt.cleanup_ring(ring); } int diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 29cb2156d32b..26b38b3ae4f3 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1023,14 +1023,14 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, return 0; } -static int -legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, - struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 flags) +int +i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, + struct intel_engine_cs *ring, + struct intel_context *ctx, + struct drm_i915_gem_execbuffer2 *args, + struct list_head *vmas, + struct drm_i915_gem_object *batch_obj, + u64 exec_start, u32 flags) { struct drm_clip_rect *cliprects = NULL; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1402,8 +1402,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } else exec_start += i915_gem_obj_offset(batch_obj, vm); - ret = legacy_ringbuffer_submission(dev, file, ring, ctx, - args, &eb->vmas, batch_obj, exec_start, flags); + ret = dev_priv->gt.do_execbuf(dev, file, ring, ctx, args, + &eb->vmas, batch_obj, exec_start, flags); /* * FIXME: We crucially rely upon the active tracking for the (ppgtt) -- GitLab From 454afebde873874b939465bfc1a294ac3697c96e Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:22 +0100 Subject: [PATCH 0137/5088] drm/i915/bdw: Skeleton for the new logical rings submission path Execlists are indeed a brave new world with respect to workload submission to the GPU. In previous version of these series, I have tried to impact the legacy ringbuffer submission path as little as possible (mostly, passing the context around and using the correct ringbuffer when I needed one) but Daniel is afraid (probably with a reason) that these changes and, especially, future ones, will end up breaking older gens. This commit and some others coming next will try to limit the damage by creating an alternative path for workload submission. The first step is here: laying out a new ring init/fini. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 5 + drivers/gpu/drm/i915/intel_lrc.c | 151 +++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_lrc.h | 12 +++ 3 files changed, 168 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 33a54cbf9a2e..9acb2469116a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4741,6 +4741,11 @@ int i915_gem_init(struct drm_device *dev) dev_priv->gt.init_rings = i915_gem_init_rings; dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer; dev_priv->gt.stop_ring = intel_stop_ring_buffer; + } else { + dev_priv->gt.do_execbuf = intel_execlists_submission; + dev_priv->gt.init_rings = intel_logical_rings_init; + dev_priv->gt.cleanup_ring = intel_logical_ring_cleanup; + dev_priv->gt.stop_ring = intel_logical_ring_stop; } i915_gem_init_userptr(dev); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a7a08a85edb3..9c2ff8f11c90 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -91,6 +91,157 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists return 0; } +int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, + struct intel_engine_cs *ring, + struct intel_context *ctx, + struct drm_i915_gem_execbuffer2 *args, + struct list_head *vmas, + struct drm_i915_gem_object *batch_obj, + u64 exec_start, u32 flags) +{ + /* TODO */ + return 0; +} + +void intel_logical_ring_stop(struct intel_engine_cs *ring) +{ + /* TODO */ +} + +void intel_logical_ring_cleanup(struct intel_engine_cs *ring) +{ + /* TODO */ +} + +static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring) +{ + /* TODO */ + return 0; +} + +static int logical_render_ring_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *ring = &dev_priv->ring[RCS]; + + ring->name = "render ring"; + ring->id = RCS; + ring->mmio_base = RENDER_RING_BASE; + ring->irq_enable_mask = + GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT; + + return logical_ring_init(dev, ring); +} + +static int logical_bsd_ring_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *ring = &dev_priv->ring[VCS]; + + ring->name = "bsd ring"; + ring->id = VCS; + ring->mmio_base = GEN6_BSD_RING_BASE; + ring->irq_enable_mask = + GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT; + + return logical_ring_init(dev, ring); +} + +static int logical_bsd2_ring_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *ring = &dev_priv->ring[VCS2]; + + ring->name = "bds2 ring"; + ring->id = VCS2; + ring->mmio_base = GEN8_BSD2_RING_BASE; + ring->irq_enable_mask = + GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT; + + return logical_ring_init(dev, ring); +} + +static int logical_blt_ring_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *ring = &dev_priv->ring[BCS]; + + ring->name = "blitter ring"; + ring->id = BCS; + ring->mmio_base = BLT_RING_BASE; + ring->irq_enable_mask = + GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT; + + return logical_ring_init(dev, ring); +} + +static int logical_vebox_ring_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *ring = &dev_priv->ring[VECS]; + + ring->name = "video enhancement ring"; + ring->id = VECS; + ring->mmio_base = VEBOX_RING_BASE; + ring->irq_enable_mask = + GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT; + + return logical_ring_init(dev, ring); +} + +int intel_logical_rings_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ret = logical_render_ring_init(dev); + if (ret) + return ret; + + if (HAS_BSD(dev)) { + ret = logical_bsd_ring_init(dev); + if (ret) + goto cleanup_render_ring; + } + + if (HAS_BLT(dev)) { + ret = logical_blt_ring_init(dev); + if (ret) + goto cleanup_bsd_ring; + } + + if (HAS_VEBOX(dev)) { + ret = logical_vebox_ring_init(dev); + if (ret) + goto cleanup_blt_ring; + } + + if (HAS_BSD2(dev)) { + ret = logical_bsd2_ring_init(dev); + if (ret) + goto cleanup_vebox_ring; + } + + ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000)); + if (ret) + goto cleanup_bsd2_ring; + + return 0; + +cleanup_bsd2_ring: + intel_logical_ring_cleanup(&dev_priv->ring[VCS2]); +cleanup_vebox_ring: + intel_logical_ring_cleanup(&dev_priv->ring[VECS]); +cleanup_blt_ring: + intel_logical_ring_cleanup(&dev_priv->ring[BCS]); +cleanup_bsd_ring: + intel_logical_ring_cleanup(&dev_priv->ring[VCS]); +cleanup_render_ring: + intel_logical_ring_cleanup(&dev_priv->ring[RCS]); + + return ret; +} + static int populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_obj, struct intel_engine_cs *ring, struct intel_ringbuffer *ringbuf) diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 3b93572431e3..bf0eff4e9f08 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -24,6 +24,11 @@ #ifndef _INTEL_LRC_H_ #define _INTEL_LRC_H_ +/* Logical Rings */ +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); + /* Logical Ring Contexts */ void intel_lr_context_free(struct intel_context *ctx); int intel_lr_context_deferred_create(struct intel_context *ctx, @@ -31,5 +36,12 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, /* 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 drm_i915_gem_execbuffer2 *args, + struct list_head *vmas, + struct drm_i915_gem_object *batch_obj, + u64 exec_start, u32 flags); #endif /* _INTEL_LRC_H_ */ -- GitLab From 48d823878d64f93163f5a949623346748bbce1b4 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:23 +0100 Subject: [PATCH 0138/5088] drm/i915/bdw: Generic logical ring init and cleanup Allocate and populate the default LRC for every ring, call gen-specific init/cleanup, init/fini the command parser and set the status page (now inside the LRC object). These are things all engines/rings have in common. Stopping the ring before cleanup and initializing the seqnos is left as a TODO task (we need more infrastructure in place before we can achieve this). v2: Check the ringbuffer backing obj for ring_is_initialized, instead of the context backing obj (similar, but not exactly the same). Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 4 -- drivers/gpu/drm/i915/intel_lrc.c | 54 ++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.c | 17 ++++++++ drivers/gpu/drm/i915/intel_ringbuffer.h | 6 +-- 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index bcb41002aa13..7a08f3e9e1ae 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -445,10 +445,6 @@ int i915_gem_context_init(struct drm_device *dev) /* NB: RCS will hold a ref for all rings */ ring->default_context = ctx; - - /* FIXME: we really only want to do this for initialized rings */ - if (i915.enable_execlists) - intel_lr_context_deferred_create(ctx, ring); } DRM_DEBUG_DRIVER("%s context support initialized\n", diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9c2ff8f11c90..ed7a4ff3bbd2 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -110,12 +110,60 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring) void intel_logical_ring_cleanup(struct intel_engine_cs *ring) { - /* TODO */ + if (!intel_ring_initialized(ring)) + return; + + /* TODO: make sure the ring is stopped */ + ring->preallocated_lazy_request = NULL; + ring->outstanding_lazy_seqno = 0; + + if (ring->cleanup) + ring->cleanup(ring); + + i915_cmd_parser_fini_ring(ring); + + if (ring->status_page.obj) { + kunmap(sg_page(ring->status_page.obj->pages->sgl)); + ring->status_page.obj = NULL; + } } static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring) { - /* TODO */ + int ret; + struct intel_context *dctx = ring->default_context; + struct drm_i915_gem_object *dctx_obj; + + /* Intentionally left blank. */ + ring->buffer = NULL; + + ring->dev = dev; + INIT_LIST_HEAD(&ring->active_list); + INIT_LIST_HEAD(&ring->request_list); + init_waitqueue_head(&ring->irq_queue); + + ret = intel_lr_context_deferred_create(dctx, ring); + if (ret) + return ret; + + /* The status page is offset 0 from the context object in LRCs. */ + dctx_obj = dctx->engine[ring->id].state; + ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(dctx_obj); + ring->status_page.page_addr = kmap(sg_page(dctx_obj->pages->sgl)); + if (ring->status_page.page_addr == NULL) + return -ENOMEM; + ring->status_page.obj = dctx_obj; + + ret = i915_cmd_parser_init_ring(ring); + if (ret) + return ret; + + if (ring->init) { + ret = ring->init(ring); + if (ret) + return ret; + } + return 0; } @@ -399,6 +447,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, int ret; WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL); + if (ctx->engine[ring->id].state) + return 0; context_size = round_up(get_lr_context_size(ring), 4096); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c35f956ed6a0..e4b97f5c5797 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -40,6 +40,23 @@ */ #define CACHELINE_BYTES 64 +bool +intel_ring_initialized(struct intel_engine_cs *ring) +{ + struct drm_device *dev = ring->dev; + + if (!dev) + return false; + + if (i915.enable_execlists) { + struct intel_context *dctx = ring->default_context; + struct intel_ringbuffer *ringbuf = dctx->engine[ring->id].ringbuf; + + return ringbuf->obj; + } else + return ring->buffer && ring->buffer->obj; +} + static inline int __ring_space(int head, int tail, int size) { int space = head - (tail + I915_RING_FREE_SPACE); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index fe9d9d9d3598..fbe54ef6a9a1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -289,11 +289,7 @@ struct intel_engine_cs { u32 (*get_cmd_length_mask)(u32 cmd_header); }; -static inline bool -intel_ring_initialized(struct intel_engine_cs *ring) -{ - return ring->buffer && ring->buffer->obj; -} +bool intel_ring_initialized(struct intel_engine_cs *ring); static inline unsigned intel_ring_flag(struct intel_engine_cs *ring) -- GitLab From 9b1136d505b1de5478e11b59ca59cf8ce2a33217 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:24 +0100 Subject: [PATCH 0139/5088] drm/i915/bdw: GEN-specific logical ring init Logical rings do not need most of the initialization their legacy ringbuffer counterparts do: we just need the pipe control object for the render ring, enable Execlists on the hardware and a few workarounds. v2: Squash with: "drm/i915: Extract pipe control fini & make init outside accesible". Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Make checkpatch happy.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 54 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 34 ++++++++++------ drivers/gpu/drm/i915/intel_ringbuffer.h | 3 ++ 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index ed7a4ff3bbd2..1a1f5f98f05b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -108,6 +108,49 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring) /* TODO */ } +static int gen8_init_common_ring(struct intel_engine_cs *ring) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RING_MODE_GEN7(ring), + _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | + _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); + POSTING_READ(RING_MODE_GEN7(ring)); + DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name); + + memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); + + return 0; +} + +static int gen8_init_render_ring(struct intel_engine_cs *ring) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ret = gen8_init_common_ring(ring); + if (ret) + return ret; + + /* We need to disable the AsyncFlip performance optimisations in order + * 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 + */ + I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); + + ret = intel_init_pipe_control(ring); + if (ret) + return ret; + + I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); + + return ret; +} + void intel_logical_ring_cleanup(struct intel_engine_cs *ring) { if (!intel_ring_initialized(ring)) @@ -178,6 +221,9 @@ static int logical_render_ring_init(struct drm_device *dev) ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT; + ring->init = gen8_init_render_ring; + ring->cleanup = intel_fini_pipe_control; + return logical_ring_init(dev, ring); } @@ -192,6 +238,8 @@ static int logical_bsd_ring_init(struct drm_device *dev) ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT; + ring->init = gen8_init_common_ring; + return logical_ring_init(dev, ring); } @@ -206,6 +254,8 @@ static int logical_bsd2_ring_init(struct drm_device *dev) ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT; + ring->init = gen8_init_common_ring; + return logical_ring_init(dev, ring); } @@ -220,6 +270,8 @@ static int logical_blt_ring_init(struct drm_device *dev) ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT; + ring->init = gen8_init_common_ring; + return logical_ring_init(dev, ring); } @@ -234,6 +286,8 @@ static int logical_vebox_ring_init(struct drm_device *dev) ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT; + ring->init = gen8_init_common_ring; + return logical_ring_init(dev, ring); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e4b97f5c5797..dab5e7c79036 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -597,8 +597,25 @@ static int init_ring_common(struct intel_engine_cs *ring) return ret; } -static int -init_pipe_control(struct intel_engine_cs *ring) +void +intel_fini_pipe_control(struct intel_engine_cs *ring) +{ + struct drm_device *dev = ring->dev; + + if (ring->scratch.obj == NULL) + return; + + if (INTEL_INFO(dev)->gen >= 5) { + kunmap(sg_page(ring->scratch.obj->pages->sgl)); + i915_gem_object_ggtt_unpin(ring->scratch.obj); + } + + drm_gem_object_unreference(&ring->scratch.obj->base); + ring->scratch.obj = NULL; +} + +int +intel_init_pipe_control(struct intel_engine_cs *ring) { int ret; @@ -673,7 +690,7 @@ static int init_render_ring(struct intel_engine_cs *ring) _MASKED_BIT_ENABLE(GFX_REPLAY_MODE)); if (INTEL_INFO(dev)->gen >= 5) { - ret = init_pipe_control(ring); + ret = intel_init_pipe_control(ring); if (ret) return ret; } @@ -708,16 +725,7 @@ static void render_ring_cleanup(struct intel_engine_cs *ring) dev_priv->semaphore_obj = NULL; } - if (ring->scratch.obj == NULL) - return; - - if (INTEL_INFO(dev)->gen >= 5) { - kunmap(sg_page(ring->scratch.obj->pages->sgl)); - i915_gem_object_ggtt_unpin(ring->scratch.obj); - } - - drm_gem_object_unreference(&ring->scratch.obj->base); - ring->scratch.obj = NULL; + intel_fini_pipe_control(ring); } static int gen8_rcs_signal(struct intel_engine_cs *signaller, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index fbe54ef6a9a1..677df0d7be48 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -381,6 +381,9 @@ 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); +void intel_fini_pipe_control(struct intel_engine_cs *ring); +int intel_init_pipe_control(struct intel_engine_cs *ring); + int intel_init_render_ring_buffer(struct drm_device *dev); int intel_init_bsd_ring_buffer(struct drm_device *dev); int intel_init_bsd2_ring_buffer(struct drm_device *dev); -- GitLab From f72a113a71ab08c4df8a5f80ab2f8a140feb81f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 7 Aug 2014 09:36:00 +0200 Subject: [PATCH 0140/5088] drm/radeon: add userptr support v8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds an IOCTL for turning a pointer supplied by userspace into a buffer object. It imposes several restrictions upon the memory being mapped: 1. It must be page aligned (both start/end addresses, i.e ptr and size). 2. It must be normal system memory, not a pointer into another map of IO space (e.g. it must not be a GTT mmapping of another object). 3. The BO is mapped into GTT, so the maximum amount of memory mapped at all times is still the GTT limit. 4. The BO is only mapped readonly for now, so no write support. 5. List of backing pages is only acquired once, so they represent a snapshot of the first use. Exporting and sharing as well as mapping of buffer objects created by this function is forbidden and results in an -EPERM. v2: squash all previous changes into first public version v3: fix tabs, map readonly, don't use MM callback any more v4: set TTM_PAGE_FLAG_SG so that TTM never messes with the pages, pin/unpin pages on bind/unbind instead of populate/unpopulate v5: rebased on 3.17-wip, IOCTL renamed to userptr, reject any unknown flags, better handle READONLY flag, improve permission check v6: fix ptr cast warning, use set_page_dirty/mark_page_accessed on unpin v7: add warning about it's availability in the API definition v8: drop access_ok check, fix VM mapping bits Signed-off-by: Christian König Reviewed-by: Alex Deucher (v4) Reviewed-by: Jérôme Glisse (v4) Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 6 + drivers/gpu/drm/radeon/radeon_cs.c | 25 ++++- drivers/gpu/drm/radeon/radeon_drv.c | 5 +- drivers/gpu/drm/radeon/radeon_gem.c | 68 ++++++++++++ drivers/gpu/drm/radeon/radeon_kms.c | 1 + drivers/gpu/drm/radeon/radeon_object.c | 3 + drivers/gpu/drm/radeon/radeon_prime.c | 10 ++ drivers/gpu/drm/radeon/radeon_ttm.c | 145 +++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_vm.c | 3 + include/uapi/drm/radeon_drm.h | 16 +++ 10 files changed, 279 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 9e1732eb402c..6f38a23a5810 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -2138,6 +2138,8 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int radeon_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); +int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, @@ -2871,6 +2873,10 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain); extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo); +extern int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, + uint32_t flags); +extern bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm); +extern bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm); extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base); extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index ee712c199b25..1321491cf499 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -78,7 +78,8 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) struct radeon_cs_chunk *chunk; struct radeon_cs_buckets buckets; unsigned i, j; - bool duplicate; + bool duplicate, need_mmap_lock = false; + int r; if (p->chunk_relocs_idx == -1) { return 0; @@ -164,6 +165,19 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) p->relocs[i].allowed_domains = domain; } + if (radeon_ttm_tt_has_userptr(p->relocs[i].robj->tbo.ttm)) { + uint32_t domain = p->relocs[i].prefered_domains; + if (!(domain & RADEON_GEM_DOMAIN_GTT)) { + DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is " + "allowed for userptr BOs\n"); + return -EINVAL; + } + need_mmap_lock = true; + domain = RADEON_GEM_DOMAIN_GTT; + p->relocs[i].prefered_domains = domain; + p->relocs[i].allowed_domains = domain; + } + p->relocs[i].tv.bo = &p->relocs[i].robj->tbo; p->relocs[i].handle = r->handle; @@ -176,8 +190,15 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) if (p->cs_flags & RADEON_CS_USE_VM) p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm, &p->validated); + if (need_mmap_lock) + down_read(¤t->mm->mmap_sem); + + r = radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring); - return radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring); + if (need_mmap_lock) + up_read(¤t->mm->mmap_sem); + + return r; } static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority) diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index a773830c6c40..5b18af926527 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -114,6 +114,9 @@ int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv); void radeon_gem_object_close(struct drm_gem_object *obj, struct drm_file *file_priv); +struct dma_buf *radeon_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *gobj, + int flags); extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags, int *vpos, int *hpos, ktime_t *stime, @@ -568,7 +571,7 @@ static struct drm_driver kms_driver = { .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_export = drm_gem_prime_export, + .gem_prime_export = radeon_gem_prime_export, .gem_prime_import = drm_gem_prime_import, .gem_prime_pin = radeon_gem_prime_pin, .gem_prime_unpin = radeon_gem_prime_unpin, diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index bfd7e1b0ff3f..993ab223b503 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -272,6 +272,65 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data, return 0; } +int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_radeon_gem_userptr *args = data; + struct drm_gem_object *gobj; + struct radeon_bo *bo; + uint32_t handle; + int r; + + if (offset_in_page(args->addr | args->size)) + return -EINVAL; + + /* we only support read only mappings for now */ + if (!(args->flags & RADEON_GEM_USERPTR_READONLY)) + return -EACCES; + + /* reject unknown flag values */ + if (args->flags & ~RADEON_GEM_USERPTR_READONLY) + return -EINVAL; + + /* readonly pages not tested on older hardware */ + if (rdev->family < CHIP_R600) + return -EINVAL; + + down_read(&rdev->exclusive_lock); + + /* create a gem object to contain this object in */ + r = radeon_gem_object_create(rdev, args->size, 0, + RADEON_GEM_DOMAIN_CPU, 0, + false, &gobj); + if (r) + goto handle_lockup; + + bo = gem_to_radeon_bo(gobj); + r = radeon_ttm_tt_set_userptr(bo->tbo.ttm, args->addr, args->flags); + if (r) + goto release_object; + + r = drm_gem_handle_create(filp, gobj, &handle); + /* drop reference from allocate - handle holds it now */ + drm_gem_object_unreference_unlocked(gobj); + if (r) + goto handle_lockup; + + args->handle = handle; + up_read(&rdev->exclusive_lock); + return 0; + +release_object: + drm_gem_object_unreference_unlocked(gobj); + +handle_lockup: + up_read(&rdev->exclusive_lock); + r = radeon_gem_handle_lockup(rdev, r); + + return r; +} + int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { @@ -315,6 +374,10 @@ int radeon_mode_dumb_mmap(struct drm_file *filp, return -ENOENT; } robj = gem_to_radeon_bo(gobj); + if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) { + drm_gem_object_unreference_unlocked(gobj); + return -EPERM; + } *offset_p = radeon_bo_mmap_offset(robj); drm_gem_object_unreference_unlocked(gobj); return 0; @@ -532,6 +595,11 @@ int radeon_gem_op_ioctl(struct drm_device *dev, void *data, return -ENOENT; } robj = gem_to_radeon_bo(gobj); + + r = -EPERM; + if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) + goto out; + r = radeon_bo_reserve(robj, false); if (unlikely(r)) goto out; diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index eb7164d07985..8309b11e674d 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -885,5 +885,6 @@ const struct drm_ioctl_desc radeon_ioctls_kms[] = { DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(RADEON_GEM_USERPTR, radeon_gem_userptr_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), }; int radeon_max_kms_ioctl = ARRAY_SIZE(radeon_ioctls_kms); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 480c87d8edc5..c73c1e320585 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -264,6 +264,9 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset, { int r, i; + if (radeon_ttm_tt_has_userptr(bo->tbo.ttm)) + return -EPERM; + if (bo->pin_count) { bo->pin_count++; if (gpu_addr) diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c index f7e48d329db3..bb18bc74b7d7 100644 --- a/drivers/gpu/drm/radeon/radeon_prime.c +++ b/drivers/gpu/drm/radeon/radeon_prime.c @@ -103,3 +103,13 @@ void radeon_gem_prime_unpin(struct drm_gem_object *obj) radeon_bo_unpin(bo); radeon_bo_unreserve(bo); } + +struct dma_buf *radeon_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *gobj, + int flags) +{ + struct radeon_bo *bo = gem_to_radeon_bo(gobj); + if (radeon_ttm_tt_has_userptr(bo->tbo.ttm)) + return ERR_PTR(-EPERM); + return drm_gem_prime_export(dev, gobj, flags); +} diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 72afe82a95c9..b20933fa35c6 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include "radeon_reg.h" #include "radeon.h" @@ -515,8 +517,92 @@ struct radeon_ttm_tt { struct ttm_dma_tt ttm; struct radeon_device *rdev; u64 offset; + + uint64_t userptr; + struct mm_struct *usermm; + uint32_t userflags; }; +/* prepare the sg table with the user pages */ +static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm) +{ + struct radeon_device *rdev = radeon_get_rdev(ttm->bdev); + struct radeon_ttm_tt *gtt = (void *)ttm; + unsigned pinned = 0, nents; + int r; + + int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY); + enum dma_data_direction direction = write ? + DMA_BIDIRECTIONAL : DMA_TO_DEVICE; + + if (current->mm != gtt->usermm) + return -EPERM; + + do { + unsigned num_pages = ttm->num_pages - pinned; + uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE; + struct page **pages = ttm->pages + pinned; + + r = get_user_pages(current, current->mm, userptr, num_pages, + write, 0, pages, NULL); + if (r < 0) + goto release_pages; + + pinned += r; + + } while (pinned < ttm->num_pages); + + r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0, + ttm->num_pages << PAGE_SHIFT, + GFP_KERNEL); + if (r) + goto release_sg; + + r = -ENOMEM; + nents = dma_map_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction); + if (nents != ttm->sg->nents) + goto release_sg; + + drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, + gtt->ttm.dma_address, ttm->num_pages); + + return 0; + +release_sg: + kfree(ttm->sg); + +release_pages: + release_pages(ttm->pages, pinned, 0); + return r; +} + +static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm) +{ + struct radeon_device *rdev = radeon_get_rdev(ttm->bdev); + struct radeon_ttm_tt *gtt = (void *)ttm; + struct scatterlist *sg; + int i; + + int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY); + enum dma_data_direction direction = write ? + DMA_BIDIRECTIONAL : DMA_TO_DEVICE; + + /* free the sg table and pages again */ + dma_unmap_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction); + + for_each_sg(ttm->sg->sgl, sg, ttm->sg->nents, i) { + struct page *page = sg_page(sg); + + if (!(gtt->userflags & RADEON_GEM_USERPTR_READONLY)) + set_page_dirty(page); + + mark_page_accessed(page); + page_cache_release(page); + } + + sg_free_table(ttm->sg); +} + static int radeon_ttm_backend_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) { @@ -525,6 +611,11 @@ static int radeon_ttm_backend_bind(struct ttm_tt *ttm, RADEON_GART_PAGE_WRITE; int r; + if (gtt->userptr) { + radeon_ttm_tt_pin_userptr(ttm); + flags &= ~RADEON_GART_PAGE_WRITE; + } + gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT); if (!ttm->num_pages) { WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", @@ -547,6 +638,10 @@ static int radeon_ttm_backend_unbind(struct ttm_tt *ttm) struct radeon_ttm_tt *gtt = (void *)ttm; radeon_gart_unbind(gtt->rdev, gtt->offset, ttm->num_pages); + + if (gtt->userptr) + radeon_ttm_tt_unpin_userptr(ttm); + return 0; } @@ -603,6 +698,16 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) if (ttm->state != tt_unpopulated) return 0; + if (gtt->userptr) { + ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL); + if (!ttm->sg) + return -ENOMEM; + + ttm->page_flags |= TTM_PAGE_FLAG_SG; + ttm->state = tt_unbound; + return 0; + } + if (slave && ttm->sg) { drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, gtt->ttm.dma_address, ttm->num_pages); @@ -652,6 +757,12 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm) unsigned i; bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); + if (gtt->userptr) { + kfree(ttm->sg); + ttm->page_flags &= ~TTM_PAGE_FLAG_SG; + return; + } + if (slave) return; @@ -680,6 +791,40 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm) ttm_pool_unpopulate(ttm); } +int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, + uint32_t flags) +{ + struct radeon_ttm_tt *gtt = (void *)ttm; + + if (gtt == NULL) + return -EINVAL; + + gtt->userptr = addr; + gtt->usermm = current->mm; + gtt->userflags = flags; + return 0; +} + +bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm) +{ + struct radeon_ttm_tt *gtt = (void *)ttm; + + if (gtt == NULL) + return false; + + return !!gtt->userptr; +} + +bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm) +{ + struct radeon_ttm_tt *gtt = (void *)ttm; + + if (gtt == NULL) + return false; + + return !!(gtt->userflags & RADEON_GEM_USERPTR_READONLY); +} + static struct ttm_bo_driver radeon_bo_driver = { .ttm_tt_create = &radeon_ttm_tt_create, .ttm_tt_populate = &radeon_ttm_tt_populate, diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index ccae4d9dc3de..0e107c5650bf 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -888,6 +888,9 @@ int radeon_vm_bo_update(struct radeon_device *rdev, bo_va->flags &= ~RADEON_VM_PAGE_VALID; bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; bo_va->flags &= ~RADEON_VM_PAGE_SNOOPED; + if (bo_va->bo && radeon_ttm_tt_is_readonly(bo_va->bo->tbo.ttm)) + bo_va->flags &= ~RADEON_VM_PAGE_WRITEABLE; + if (mem) { addr = mem->start << PAGE_SHIFT; if (mem->mem_type != TTM_PL_SYSTEM) { diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h index 509b2d7a41b7..3a9f20930372 100644 --- a/include/uapi/drm/radeon_drm.h +++ b/include/uapi/drm/radeon_drm.h @@ -511,6 +511,7 @@ typedef struct { #define DRM_RADEON_GEM_BUSY 0x2a #define DRM_RADEON_GEM_VA 0x2b #define DRM_RADEON_GEM_OP 0x2c +#define DRM_RADEON_GEM_USERPTR 0x2d #define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t) #define DRM_IOCTL_RADEON_CP_START DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_START) @@ -554,6 +555,7 @@ typedef struct { #define DRM_IOCTL_RADEON_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_BUSY, struct drm_radeon_gem_busy) #define DRM_IOCTL_RADEON_GEM_VA DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_VA, struct drm_radeon_gem_va) #define DRM_IOCTL_RADEON_GEM_OP DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_OP, struct drm_radeon_gem_op) +#define DRM_IOCTL_RADEON_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_USERPTR, struct drm_radeon_gem_userptr) typedef struct drm_radeon_init { enum { @@ -808,6 +810,20 @@ struct drm_radeon_gem_create { uint32_t flags; }; +/* + * This is not a reliable API and you should expect it to fail for any + * number of reasons and have fallback path that do not use userptr to + * perform any operation. + */ +#define RADEON_GEM_USERPTR_READONLY (1 << 0) + +struct drm_radeon_gem_userptr { + uint64_t addr; + uint64_t size; + uint32_t flags; + uint32_t handle; +}; + #define RADEON_TILING_MACRO 0x1 #define RADEON_TILING_MICRO 0x2 #define RADEON_TILING_SWAP_16BIT 0x4 -- GitLab From ddd00e33e17a62c5f44377ab42e7562ccfae7bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 7 Aug 2014 09:36:01 +0200 Subject: [PATCH 0141/5088] drm/radeon: add userptr flag to limit it to anonymous memory v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid problems with writeback by limiting userptr to anonymous memory. v2: add commit and code comments Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_gem.c | 3 ++- drivers/gpu/drm/radeon/radeon_ttm.c | 10 ++++++++++ include/uapi/drm/radeon_drm.h | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 993ab223b503..032736b429bf 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -290,7 +290,8 @@ int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, return -EACCES; /* reject unknown flag values */ - if (args->flags & ~RADEON_GEM_USERPTR_READONLY) + if (args->flags & ~(RADEON_GEM_USERPTR_READONLY | + RADEON_GEM_USERPTR_ANONONLY)) return -EINVAL; /* readonly pages not tested on older hardware */ diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index b20933fa35c6..12e37b1ddc40 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -538,6 +538,16 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm) if (current->mm != gtt->usermm) return -EPERM; + if (gtt->userflags & RADEON_GEM_USERPTR_ANONONLY) { + /* check that we only pin down anonymous memory + to prevent problems with writeback */ + unsigned long end = gtt->userptr + ttm->num_pages * PAGE_SIZE; + struct vm_area_struct *vma; + vma = find_vma(gtt->usermm, gtt->userptr); + if (!vma || vma->vm_file || vma->vm_end < end) + return -EPERM; + } + do { unsigned num_pages = ttm->num_pages - pinned; uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE; diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h index 3a9f20930372..9720e1a36848 100644 --- a/include/uapi/drm/radeon_drm.h +++ b/include/uapi/drm/radeon_drm.h @@ -816,6 +816,7 @@ struct drm_radeon_gem_create { * perform any operation. */ #define RADEON_GEM_USERPTR_READONLY (1 << 0) +#define RADEON_GEM_USERPTR_ANONONLY (1 << 1) struct drm_radeon_gem_userptr { uint64_t addr; -- GitLab From 2a84a4476d6e13de72472f6ca4338aed0a8269b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 7 Aug 2014 09:36:02 +0200 Subject: [PATCH 0142/5088] drm/radeon: add userptr flag to directly validate the BO to GTT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way we test userptr availability at BO creation time instead of first use. Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_gem.c | 18 +++++++++++++++++- include/uapi/drm/radeon_drm.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 032736b429bf..450656027aba 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -291,7 +291,7 @@ int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, /* reject unknown flag values */ if (args->flags & ~(RADEON_GEM_USERPTR_READONLY | - RADEON_GEM_USERPTR_ANONONLY)) + RADEON_GEM_USERPTR_ANONONLY | RADEON_GEM_USERPTR_VALIDATE)) return -EINVAL; /* readonly pages not tested on older hardware */ @@ -312,6 +312,22 @@ int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, if (r) goto release_object; + if (args->flags & RADEON_GEM_USERPTR_VALIDATE) { + down_read(¤t->mm->mmap_sem); + r = radeon_bo_reserve(bo, true); + if (r) { + up_read(¤t->mm->mmap_sem); + goto release_object; + } + + radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_GTT); + r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); + radeon_bo_unreserve(bo); + up_read(¤t->mm->mmap_sem); + if (r) + goto release_object; + } + r = drm_gem_handle_create(filp, gobj, &handle); /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(gobj); diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h index 9720e1a36848..5dc61c2d4c73 100644 --- a/include/uapi/drm/radeon_drm.h +++ b/include/uapi/drm/radeon_drm.h @@ -817,6 +817,7 @@ struct drm_radeon_gem_create { */ #define RADEON_GEM_USERPTR_READONLY (1 << 0) #define RADEON_GEM_USERPTR_ANONONLY (1 << 1) +#define RADEON_GEM_USERPTR_VALIDATE (1 << 2) struct drm_radeon_gem_userptr { uint64_t addr; -- GitLab From 341cb9e426fac32523427c80c67543a16be46605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 7 Aug 2014 09:36:03 +0200 Subject: [PATCH 0143/5088] drm/radeon: add userptr flag to register MMU notifier v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Whenever userspace mapping related to our userptr change we wait for it to become idle and unmap it from GTT. v2: rebased, fix mutex unlock in error path v3: improve commit message Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/radeon/Makefile | 2 +- drivers/gpu/drm/radeon/radeon.h | 12 ++ drivers/gpu/drm/radeon/radeon_device.c | 2 + drivers/gpu/drm/radeon/radeon_gem.c | 9 +- drivers/gpu/drm/radeon/radeon_mn.c | 272 +++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_object.c | 1 + include/uapi/drm/radeon_drm.h | 1 + 8 files changed, 298 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/radeon/radeon_mn.c diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index b066bb3ca01a..358b6e8697e9 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -115,6 +115,7 @@ config DRM_RADEON select HWMON select BACKLIGHT_CLASS_DEVICE select INTERVAL_TREE + select MMU_NOTIFIER help Choose this option if you have an ATI Radeon graphics card. There are both PCI and AGP versions. You don't need to choose this to diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 0013ad0db9ef..c7fa1aeb8c3f 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -80,7 +80,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \ rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \ trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \ - ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o + ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o radeon_mn.o # add async DMA block radeon-y += \ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 6f38a23a5810..542da8208674 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -487,6 +488,9 @@ struct radeon_bo { struct ttm_bo_kmap_obj dma_buf_vmap; pid_t pid; + + struct radeon_mn *mn; + struct interval_tree_node mn_it; }; #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base) @@ -1725,6 +1729,11 @@ void radeon_test_ring_sync(struct radeon_device *rdev, struct radeon_ring *cpB); void radeon_test_syncing(struct radeon_device *rdev); +/* + * MMU Notifier + */ +int radeon_mn_register(struct radeon_bo *bo, unsigned long addr); +void radeon_mn_unregister(struct radeon_bo *bo); /* * Debugfs @@ -2372,6 +2381,9 @@ struct radeon_device { /* tracking pinned memory */ u64 vram_pin_size; u64 gart_pin_size; + + struct mutex mn_lock; + DECLARE_HASHTABLE(mn_hash, 7); }; bool radeon_is_px(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index c8ea050c8fa4..c58f84f3c6a5 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1270,6 +1270,8 @@ int radeon_device_init(struct radeon_device *rdev, init_rwsem(&rdev->pm.mclk_lock); init_rwsem(&rdev->exclusive_lock); init_waitqueue_head(&rdev->irq.vblank_queue); + mutex_init(&rdev->mn_lock); + hash_init(rdev->mn_hash); r = radeon_gem_init(rdev); if (r) return r; diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 450656027aba..2a6fbf101cf0 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -291,7 +291,8 @@ int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, /* reject unknown flag values */ if (args->flags & ~(RADEON_GEM_USERPTR_READONLY | - RADEON_GEM_USERPTR_ANONONLY | RADEON_GEM_USERPTR_VALIDATE)) + RADEON_GEM_USERPTR_ANONONLY | RADEON_GEM_USERPTR_VALIDATE | + RADEON_GEM_USERPTR_REGISTER)) return -EINVAL; /* readonly pages not tested on older hardware */ @@ -312,6 +313,12 @@ int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, if (r) goto release_object; + if (args->flags & RADEON_GEM_USERPTR_REGISTER) { + r = radeon_mn_register(bo, args->addr); + if (r) + goto release_object; + } + if (args->flags & RADEON_GEM_USERPTR_VALIDATE) { down_read(¤t->mm->mmap_sem); r = radeon_bo_reserve(bo, true); diff --git a/drivers/gpu/drm/radeon/radeon_mn.c b/drivers/gpu/drm/radeon/radeon_mn.c new file mode 100644 index 000000000000..0157bc2f11f8 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_mn.c @@ -0,0 +1,272 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ +/* + * Authors: + * Christian König + */ + +#include +#include +#include +#include +#include + +#include "radeon.h" + +struct radeon_mn { + /* constant after initialisation */ + struct radeon_device *rdev; + struct mm_struct *mm; + struct mmu_notifier mn; + + /* only used on destruction */ + struct work_struct work; + + /* protected by rdev->mn_lock */ + struct hlist_node node; + + /* objects protected by lock */ + struct mutex lock; + struct rb_root objects; +}; + +/** + * radeon_mn_destroy - destroy the rmn + * + * @work: previously sheduled work item + * + * Lazy destroys the notifier from a work item + */ +static void radeon_mn_destroy(struct work_struct *work) +{ + struct radeon_mn *rmn = container_of(work, struct radeon_mn, work); + struct radeon_device *rdev = rmn->rdev; + struct radeon_bo *bo, *next; + + mutex_lock(&rdev->mn_lock); + mutex_lock(&rmn->lock); + hash_del(&rmn->node); + rbtree_postorder_for_each_entry_safe(bo, next, &rmn->objects, mn_it.rb) { + interval_tree_remove(&bo->mn_it, &rmn->objects); + bo->mn = NULL; + } + mutex_unlock(&rmn->lock); + mutex_unlock(&rdev->mn_lock); + mmu_notifier_unregister(&rmn->mn, rmn->mm); + kfree(rmn); +} + +/** + * radeon_mn_release - callback to notify about mm destruction + * + * @mn: our notifier + * @mn: the mm this callback is about + * + * Shedule a work item to lazy destroy our notifier. + */ +static void radeon_mn_release(struct mmu_notifier *mn, + struct mm_struct *mm) +{ + struct radeon_mn *rmn = container_of(mn, struct radeon_mn, mn); + INIT_WORK(&rmn->work, radeon_mn_destroy); + schedule_work(&rmn->work); +} + +/** + * radeon_mn_invalidate_range_start - callback to notify about mm change + * + * @mn: our notifier + * @mn: the mm this callback is about + * @start: start of updated range + * @end: end of updated range + * + * We block for all BOs between start and end to be idle and + * unmap them by move them into system domain again. + */ +static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn, + struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct radeon_mn *rmn = container_of(mn, struct radeon_mn, mn); + struct interval_tree_node *it; + + /* notification is exclusive, but interval is inclusive */ + end -= 1; + + mutex_lock(&rmn->lock); + + it = interval_tree_iter_first(&rmn->objects, start, end); + while (it) { + struct radeon_bo *bo; + int r; + + bo = container_of(it, struct radeon_bo, mn_it); + it = interval_tree_iter_next(it, start, end); + + r = radeon_bo_reserve(bo, true); + if (r) { + DRM_ERROR("(%d) failed to reserve user bo\n", r); + continue; + } + + if (bo->tbo.sync_obj) { + r = radeon_fence_wait(bo->tbo.sync_obj, false); + if (r) + DRM_ERROR("(%d) failed to wait for user bo\n", r); + } + + radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU); + r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); + if (r) + DRM_ERROR("(%d) failed to validate user bo\n", r); + + radeon_bo_unreserve(bo); + } + + mutex_unlock(&rmn->lock); +} + +static const struct mmu_notifier_ops radeon_mn_ops = { + .release = radeon_mn_release, + .invalidate_range_start = radeon_mn_invalidate_range_start, +}; + +/** + * radeon_mn_get - create notifier context + * + * @rdev: radeon device pointer + * + * Creates a notifier context for current->mm. + */ +static struct radeon_mn *radeon_mn_get(struct radeon_device *rdev) +{ + struct mm_struct *mm = current->mm; + struct radeon_mn *rmn; + int r; + + down_write(&mm->mmap_sem); + mutex_lock(&rdev->mn_lock); + + hash_for_each_possible(rdev->mn_hash, rmn, node, (unsigned long)mm) + if (rmn->mm == mm) + goto release_locks; + + rmn = kzalloc(sizeof(*rmn), GFP_KERNEL); + if (!rmn) { + rmn = ERR_PTR(-ENOMEM); + goto release_locks; + } + + rmn->rdev = rdev; + rmn->mm = mm; + rmn->mn.ops = &radeon_mn_ops; + mutex_init(&rmn->lock); + rmn->objects = RB_ROOT; + + r = __mmu_notifier_register(&rmn->mn, mm); + if (r) + goto free_rmn; + + hash_add(rdev->mn_hash, &rmn->node, (unsigned long)mm); + +release_locks: + mutex_unlock(&rdev->mn_lock); + up_write(&mm->mmap_sem); + + return rmn; + +free_rmn: + mutex_unlock(&rdev->mn_lock); + up_write(&mm->mmap_sem); + kfree(rmn); + + return ERR_PTR(r); +} + +/** + * radeon_mn_register - register a BO for notifier updates + * + * @bo: radeon buffer object + * @addr: userptr addr we should monitor + * + * Registers an MMU notifier for the given BO at the specified address. + * Returns 0 on success, -ERRNO if anything goes wrong. + */ +int radeon_mn_register(struct radeon_bo *bo, unsigned long addr) +{ + unsigned long end = addr + radeon_bo_size(bo) - 1; + struct radeon_device *rdev = bo->rdev; + struct radeon_mn *rmn; + struct interval_tree_node *it; + + rmn = radeon_mn_get(rdev); + if (IS_ERR(rmn)) + return PTR_ERR(rmn); + + mutex_lock(&rmn->lock); + + it = interval_tree_iter_first(&rmn->objects, addr, end); + if (it) { + mutex_unlock(&rmn->lock); + return -EEXIST; + } + + bo->mn = rmn; + bo->mn_it.start = addr; + bo->mn_it.last = end; + interval_tree_insert(&bo->mn_it, &rmn->objects); + + mutex_unlock(&rmn->lock); + + return 0; +} + +/** + * radeon_mn_unregister - unregister a BO for notifier updates + * + * @bo: radeon buffer object + * + * Remove any registration of MMU notifier updates from the buffer object. + */ +void radeon_mn_unregister(struct radeon_bo *bo) +{ + struct radeon_device *rdev = bo->rdev; + struct radeon_mn *rmn; + + mutex_lock(&rdev->mn_lock); + rmn = bo->mn; + if (rmn == NULL) { + mutex_unlock(&rdev->mn_lock); + return; + } + + mutex_lock(&rmn->lock); + interval_tree_remove(&bo->mn_it, &rmn->objects); + bo->mn = NULL; + mutex_unlock(&rmn->lock); + mutex_unlock(&rdev->mn_lock); +} diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index c73c1e320585..287523807989 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -75,6 +75,7 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo) bo = container_of(tbo, struct radeon_bo, tbo); radeon_update_memory_usage(bo, bo->tbo.mem.mem_type, -1); + radeon_mn_unregister(bo); mutex_lock(&bo->rdev->gem.mutex); list_del_init(&bo->list); diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h index 5dc61c2d4c73..c77495ffc44f 100644 --- a/include/uapi/drm/radeon_drm.h +++ b/include/uapi/drm/radeon_drm.h @@ -818,6 +818,7 @@ struct drm_radeon_gem_create { #define RADEON_GEM_USERPTR_READONLY (1 << 0) #define RADEON_GEM_USERPTR_ANONONLY (1 << 1) #define RADEON_GEM_USERPTR_VALIDATE (1 << 2) +#define RADEON_GEM_USERPTR_REGISTER (1 << 3) struct drm_radeon_gem_userptr { uint64_t addr; -- GitLab From bd645e4314b95b21146aa6ff893d783de20c4e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 7 Aug 2014 09:36:04 +0200 Subject: [PATCH 0144/5088] drm/radeon: allow userptr write access under certain conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It needs to be anonymous memory (no file mappings) and we are requried to install an MMU notifier. Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_gem.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 2a6fbf101cf0..01b58941acd4 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -285,19 +285,24 @@ int radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, if (offset_in_page(args->addr | args->size)) return -EINVAL; - /* we only support read only mappings for now */ - if (!(args->flags & RADEON_GEM_USERPTR_READONLY)) - return -EACCES; - /* reject unknown flag values */ if (args->flags & ~(RADEON_GEM_USERPTR_READONLY | RADEON_GEM_USERPTR_ANONONLY | RADEON_GEM_USERPTR_VALIDATE | RADEON_GEM_USERPTR_REGISTER)) return -EINVAL; - /* readonly pages not tested on older hardware */ - if (rdev->family < CHIP_R600) - return -EINVAL; + if (args->flags & RADEON_GEM_USERPTR_READONLY) { + /* readonly pages not tested on older hardware */ + if (rdev->family < CHIP_R600) + return -EINVAL; + + } else if (!(args->flags & RADEON_GEM_USERPTR_ANONONLY) || + !(args->flags & RADEON_GEM_USERPTR_REGISTER)) { + + /* if we want to write to it we must require anonymous + memory and install a MMU notifier */ + return -EACCES; + } down_read(&rdev->exclusive_lock); -- GitLab From e94e37ad19c74b4c2569d556cda9da4a03d4e3f8 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:25 +0100 Subject: [PATCH 0145/5088] drm/i915/bdw: GEN-specific logical ring set/get seqno No mistery here: the seqno is still retrieved from the engine's HW status page (the one in the default context. For the moment, I see no reason to worry about other context's HWS page). Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 1a1f5f98f05b..c9518c6261de 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -151,6 +151,16 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring) return ret; } +static u32 gen8_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency) +{ + return intel_read_status_page(ring, I915_GEM_HWS_INDEX); +} + +static void gen8_set_seqno(struct intel_engine_cs *ring, u32 seqno) +{ + intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno); +} + void intel_logical_ring_cleanup(struct intel_engine_cs *ring) { if (!intel_ring_initialized(ring)) @@ -223,6 +233,8 @@ static int logical_render_ring_init(struct drm_device *dev) ring->init = gen8_init_render_ring; ring->cleanup = intel_fini_pipe_control; + ring->get_seqno = gen8_get_seqno; + ring->set_seqno = gen8_set_seqno; return logical_ring_init(dev, ring); } @@ -239,6 +251,8 @@ static int logical_bsd_ring_init(struct drm_device *dev) GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT; ring->init = gen8_init_common_ring; + ring->get_seqno = gen8_get_seqno; + ring->set_seqno = gen8_set_seqno; return logical_ring_init(dev, ring); } @@ -255,6 +269,8 @@ static int logical_bsd2_ring_init(struct drm_device *dev) GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT; ring->init = gen8_init_common_ring; + ring->get_seqno = gen8_get_seqno; + ring->set_seqno = gen8_set_seqno; return logical_ring_init(dev, ring); } @@ -271,6 +287,8 @@ static int logical_blt_ring_init(struct drm_device *dev) GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT; ring->init = gen8_init_common_ring; + ring->get_seqno = gen8_get_seqno; + ring->set_seqno = gen8_set_seqno; return logical_ring_init(dev, ring); } @@ -287,6 +305,8 @@ static int logical_vebox_ring_init(struct drm_device *dev) GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT; ring->init = gen8_init_common_ring; + ring->get_seqno = gen8_get_seqno; + ring->set_seqno = gen8_set_seqno; return logical_ring_init(dev, ring); } -- GitLab From 26fbb77445bd402417f42936f68c0da26d33855d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 11 Aug 2014 18:37:37 +0300 Subject: [PATCH 0146/5088] drm/i915: Make hpd debug messages less cryptic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't print raw numbers, use port_name() and tell the user whether it's long or short without having to figure out what the other magic number means. Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 4 +++- drivers/gpu/drm/i915/intel_dp.c | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f0d24db76e72..36eb1f234608 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1777,7 +1777,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev, long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; } - DRM_DEBUG_DRIVER("digital hpd port %d %d\n", port, long_hpd); + 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) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3b88255d87dc..def55cdfef25 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4041,7 +4041,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) if (intel_dig_port->base.type != INTEL_OUTPUT_EDP) intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT; - DRM_DEBUG_KMS("got hpd irq on port %d - %s\n", intel_dig_port->port, + DRM_DEBUG_KMS("got hpd irq on port %c - %s\n", + port_name(intel_dig_port->port), long_hpd ? "long" : "short"); if (long_hpd) { -- GitLab From 82e104cc266c6da30a30fc5028b2f0236c669cd7 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:26 +0100 Subject: [PATCH 0147/5088] drm/i915/bdw: New logical ring submission mechanism Well, new-ish: if all this code looks familiar, that's because it's a clone of the existing submission mechanism (with some modifications here and there to adapt it to LRCs and Execlists). And why did we do this instead of reusing code, one might wonder? Well, there are some fears that the differences are big enough that they will end up breaking all platforms. Also, Execlists offer several advantages, like control over when the GPU is done with a given workload, that can help simplify the submission mechanism, no doubt. I am interested in getting Execlists to work first and foremost, but in the future this parallel submission mechanism will help us to fine tune the mechanism without affecting old gens. v2: Pass the ringbuffer only (whenever possible). Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Appease checkpatch. Again. And drop the legacy sarea gunk that somehow crept in.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 189 ++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_lrc.h | 13 ++ drivers/gpu/drm/i915/intel_ringbuffer.c | 22 +-- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 + 4 files changed, 217 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index c9518c6261de..31025847d680 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -108,6 +108,195 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring) /* TODO */ } +void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf) +{ + intel_logical_ring_advance(ringbuf); + + if (intel_ring_stopped(ringbuf->ring)) + return; + + /* TODO: how to submit a context to the ELSP is not here yet */ +} + +static int logical_ring_alloc_seqno(struct intel_engine_cs *ring) +{ + if (ring->outstanding_lazy_seqno) + return 0; + + if (ring->preallocated_lazy_request == NULL) { + struct drm_i915_gem_request *request; + + request = kmalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return -ENOMEM; + + ring->preallocated_lazy_request = request; + } + + return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); +} + +static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, + int bytes) +{ + struct intel_engine_cs *ring = ringbuf->ring; + struct drm_i915_gem_request *request; + u32 seqno = 0; + int ret; + + if (ringbuf->last_retired_head != -1) { + ringbuf->head = ringbuf->last_retired_head; + ringbuf->last_retired_head = -1; + + ringbuf->space = intel_ring_space(ringbuf); + if (ringbuf->space >= bytes) + return 0; + } + + list_for_each_entry(request, &ring->request_list, list) { + if (__intel_ring_space(request->tail, ringbuf->tail, + ringbuf->size) >= bytes) { + seqno = request->seqno; + break; + } + } + + if (seqno == 0) + return -ENOSPC; + + ret = i915_wait_seqno(ring, seqno); + if (ret) + return ret; + + /* TODO: make sure we update the right ringbuffer's last_retired_head + * when retiring requests */ + i915_gem_retire_requests_ring(ring); + ringbuf->head = ringbuf->last_retired_head; + ringbuf->last_retired_head = -1; + + ringbuf->space = intel_ring_space(ringbuf); + return 0; +} + +static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, + int bytes) +{ + struct intel_engine_cs *ring = ringbuf->ring; + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long end; + int ret; + + ret = logical_ring_wait_request(ringbuf, bytes); + if (ret != -ENOSPC) + return ret; + + /* Force the context submission in case we have been skipping it */ + intel_logical_ring_advance_and_submit(ringbuf); + + /* With GEM the hangcheck timer should kick us out of the loop, + * leaving it early runs the risk of corrupting GEM state (due + * to running on almost untested codepaths). But on resume + * timers don't work yet, so prevent a complete hang in that + * case by choosing an insanely large timeout. */ + end = jiffies + 60 * HZ; + + do { + ringbuf->head = I915_READ_HEAD(ring); + ringbuf->space = intel_ring_space(ringbuf); + if (ringbuf->space >= bytes) { + ret = 0; + break; + } + + msleep(1); + + if (dev_priv->mm.interruptible && signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + ret = i915_gem_check_wedge(&dev_priv->gpu_error, + dev_priv->mm.interruptible); + if (ret) + break; + + if (time_after(jiffies, end)) { + ret = -EBUSY; + break; + } + } while (1); + + return ret; +} + +static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf) +{ + uint32_t __iomem *virt; + int rem = ringbuf->size - ringbuf->tail; + + if (ringbuf->space < rem) { + int ret = logical_ring_wait_for_space(ringbuf, rem); + + if (ret) + return ret; + } + + virt = ringbuf->virtual_start + ringbuf->tail; + rem /= 4; + while (rem--) + iowrite32(MI_NOOP, virt++); + + ringbuf->tail = 0; + ringbuf->space = intel_ring_space(ringbuf); + + return 0; +} + +static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, int bytes) +{ + int ret; + + if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { + ret = logical_ring_wrap_buffer(ringbuf); + if (unlikely(ret)) + return ret; + } + + if (unlikely(ringbuf->space < bytes)) { + ret = logical_ring_wait_for_space(ringbuf, bytes); + if (unlikely(ret)) + return ret; + } + + return 0; +} + +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords) +{ + struct intel_engine_cs *ring = ringbuf->ring; + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + ret = i915_gem_check_wedge(&dev_priv->gpu_error, + dev_priv->mm.interruptible); + if (ret) + return ret; + + ret = logical_ring_prepare(ringbuf, num_dwords * sizeof(uint32_t)); + if (ret) + return ret; + + /* Preallocate the olr before touching the ring */ + ret = logical_ring_alloc_seqno(ring); + if (ret) + return ret; + + ringbuf->space -= num_dwords * sizeof(uint32_t); + return 0; +} + static int gen8_init_common_ring(struct intel_engine_cs *ring) { struct drm_device *dev = ring->dev; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index bf0eff4e9f08..4e032875c1fd 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -29,6 +29,19 @@ 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); +void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf); +static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf) +{ + ringbuf->tail &= ringbuf->size - 1; +} +static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf, + u32 data) +{ + iowrite32(data, ringbuf->virtual_start + ringbuf->tail); + ringbuf->tail += 4; +} +int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords); + /* Logical Ring Contexts */ void intel_lr_context_free(struct intel_context *ctx); int intel_lr_context_deferred_create(struct intel_context *ctx, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index dab5e7c79036..0bfa018fab20 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -57,7 +57,7 @@ intel_ring_initialized(struct intel_engine_cs *ring) return ring->buffer && ring->buffer->obj; } -static inline int __ring_space(int head, int tail, int size) +int __intel_ring_space(int head, int tail, int size) { int space = head - (tail + I915_RING_FREE_SPACE); if (space < 0) @@ -65,12 +65,13 @@ static inline int __ring_space(int head, int tail, int size) return space; } -static inline int ring_space(struct intel_ringbuffer *ringbuf) +int intel_ring_space(struct intel_ringbuffer *ringbuf) { - return __ring_space(ringbuf->head & HEAD_ADDR, ringbuf->tail, ringbuf->size); + return __intel_ring_space(ringbuf->head & HEAD_ADDR, + ringbuf->tail, ringbuf->size); } -static bool intel_ring_stopped(struct intel_engine_cs *ring) +bool intel_ring_stopped(struct intel_engine_cs *ring) { struct drm_i915_private *dev_priv = ring->dev->dev_private; return dev_priv->gpu_error.stop_rings & intel_ring_flag(ring); @@ -585,7 +586,7 @@ static int init_ring_common(struct intel_engine_cs *ring) else { ringbuf->head = I915_READ_HEAD(ring); ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR; - ringbuf->space = ring_space(ringbuf); + ringbuf->space = intel_ring_space(ringbuf); ringbuf->last_retired_head = -1; } @@ -1702,13 +1703,14 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n) ringbuf->head = ringbuf->last_retired_head; ringbuf->last_retired_head = -1; - ringbuf->space = ring_space(ringbuf); + ringbuf->space = intel_ring_space(ringbuf); if (ringbuf->space >= n) return 0; } list_for_each_entry(request, &ring->request_list, list) { - if (__ring_space(request->tail, ringbuf->tail, ringbuf->size) >= n) { + if (__intel_ring_space(request->tail, ringbuf->tail, + ringbuf->size) >= n) { seqno = request->seqno; break; } @@ -1725,7 +1727,7 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n) ringbuf->head = ringbuf->last_retired_head; ringbuf->last_retired_head = -1; - ringbuf->space = ring_space(ringbuf); + ringbuf->space = intel_ring_space(ringbuf); return 0; } @@ -1754,7 +1756,7 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n) trace_i915_ring_wait_begin(ring); do { ringbuf->head = I915_READ_HEAD(ring); - ringbuf->space = ring_space(ringbuf); + ringbuf->space = intel_ring_space(ringbuf); if (ringbuf->space >= n) { ret = 0; break; @@ -1806,7 +1808,7 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) iowrite32(MI_NOOP, virt++); ringbuf->tail = 0; - ringbuf->space = ring_space(ringbuf); + ringbuf->space = intel_ring_space(ringbuf); return 0; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 677df0d7be48..81bad364e36d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -374,6 +374,9 @@ static inline void intel_ring_advance(struct intel_engine_cs *ring) struct intel_ringbuffer *ringbuf = ring->buffer; ringbuf->tail &= ringbuf->size - 1; } +int __intel_ring_space(int head, int tail, int size); +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); -- GitLab From 4da46e1e5bb7e7396fad172cdaffbe496562f3d8 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:27 +0100 Subject: [PATCH 0148/5088] drm/i915/bdw: GEN-specific logical ring emit request Very similar to the legacy add_request, only modified to account for logical ringbuffer. v2: Use MI_GLOBAL_GTT, as suggested by Brad Volkin. v3: Unify render and non-render in the same function, as noticed by Brad Volkin. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_lrc.c | 31 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +++ 3 files changed, 35 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c1d24242a02d..3388afb90a93 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -272,6 +272,7 @@ #define MI_SEMAPHORE_POLL (1<<15) #define MI_SEMAPHORE_SAD_GTE_SDD (1<<12) #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) +#define MI_STORE_DWORD_IMM_GEN8 MI_INSTR(0x20, 2) #define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ #define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) #define MI_STORE_DWORD_INDEX_SHIFT 2 diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 31025847d680..94f8b4087642 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -350,6 +350,32 @@ 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 intel_engine_cs *ring = ringbuf->ring; + u32 cmd; + int ret; + + ret = intel_logical_ring_begin(ringbuf, 6); + if (ret) + return ret; + + cmd = MI_STORE_DWORD_IMM_GEN8; + cmd |= MI_GLOBAL_GTT; + + intel_logical_ring_emit(ringbuf, cmd); + intel_logical_ring_emit(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, ring->outstanding_lazy_seqno); + intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT); + intel_logical_ring_emit(ringbuf, MI_NOOP); + intel_logical_ring_advance_and_submit(ringbuf); + + return 0; +} + void intel_logical_ring_cleanup(struct intel_engine_cs *ring) { if (!intel_ring_initialized(ring)) @@ -424,6 +450,7 @@ static int logical_render_ring_init(struct drm_device *dev) ring->cleanup = intel_fini_pipe_control; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; + ring->emit_request = gen8_emit_request; return logical_ring_init(dev, ring); } @@ -442,6 +469,7 @@ static int logical_bsd_ring_init(struct drm_device *dev) ring->init = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; + ring->emit_request = gen8_emit_request; return logical_ring_init(dev, ring); } @@ -460,6 +488,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev) ring->init = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; + ring->emit_request = gen8_emit_request; return logical_ring_init(dev, ring); } @@ -478,6 +507,7 @@ static int logical_blt_ring_init(struct drm_device *dev) ring->init = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; + ring->emit_request = gen8_emit_request; return logical_ring_init(dev, ring); } @@ -496,6 +526,7 @@ static int logical_vebox_ring_init(struct drm_device *dev) ring->init = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; + ring->emit_request = gen8_emit_request; return logical_ring_init(dev, ring); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 81bad364e36d..467885159a80 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -216,6 +216,9 @@ struct intel_engine_cs { unsigned int num_dwords); } semaphore; + /* Execlists */ + int (*emit_request)(struct intel_ringbuffer *ringbuf); + /** * List of objects currently involved in rendering from the * ringbuffer. -- GitLab From 4712274c362b7730a1c6e01c9a51a6d46f5b7f43 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:28 +0100 Subject: [PATCH 0149/5088] drm/i915/bdw: GEN-specific logical ring emit flush Same as the legacy-style ring->flush. v2: The BSD invalidate bit still exists in GEN8! Add it for the VCS rings (but still consolidate the blt and bsd ring flushes into one). This was noticed by Brad Volkin. v3: The command for BSD and for other rings is slightly different: get it exactly the same as in gen6_ring_flush + gen6_bsd_ring_flush Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Checkpatch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 85 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 7 -- drivers/gpu/drm/i915/intel_ringbuffer.h | 10 +++ 3 files changed, 95 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 94f8b4087642..a88fa6e9360b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -340,6 +340,86 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring) return ret; } +static int gen8_emit_flush(struct intel_ringbuffer *ringbuf, + u32 invalidate_domains, + u32 unused) +{ + 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, 4); + if (ret) + return ret; + + cmd = MI_FLUSH_DW + 1; + + if (ring == &dev_priv->ring[VCS]) { + if (invalidate_domains & I915_GEM_GPU_DOMAINS) + cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD | + MI_FLUSH_DW_STORE_INDEX | + MI_FLUSH_DW_OP_STOREDW; + } else { + if (invalidate_domains & I915_GEM_DOMAIN_RENDER) + cmd |= MI_INVALIDATE_TLB | MI_FLUSH_DW_STORE_INDEX | + MI_FLUSH_DW_OP_STOREDW; + } + + intel_logical_ring_emit(ringbuf, cmd); + intel_logical_ring_emit(ringbuf, + I915_GEM_HWS_SCRATCH_ADDR | + MI_FLUSH_DW_USE_GTT); + intel_logical_ring_emit(ringbuf, 0); /* upper addr */ + intel_logical_ring_emit(ringbuf, 0); /* value */ + intel_logical_ring_advance(ringbuf); + + return 0; +} + +static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf, + u32 invalidate_domains, + u32 flush_domains) +{ + struct intel_engine_cs *ring = ringbuf->ring; + u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; + u32 flags = 0; + int ret; + + flags |= PIPE_CONTROL_CS_STALL; + + if (flush_domains) { + flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH; + flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH; + } + + if (invalidate_domains) { + flags |= PIPE_CONTROL_TLB_INVALIDATE; + flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE; + flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE; + flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE; + flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE; + flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE; + flags |= PIPE_CONTROL_QW_WRITE; + flags |= PIPE_CONTROL_GLOBAL_GTT_IVB; + } + + ret = intel_logical_ring_begin(ringbuf, 6); + if (ret) + return ret; + + intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6)); + intel_logical_ring_emit(ringbuf, flags); + intel_logical_ring_emit(ringbuf, scratch_addr); + intel_logical_ring_emit(ringbuf, 0); + intel_logical_ring_emit(ringbuf, 0); + intel_logical_ring_emit(ringbuf, 0); + intel_logical_ring_advance(ringbuf); + + return 0; +} + static u32 gen8_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency) { return intel_read_status_page(ring, I915_GEM_HWS_INDEX); @@ -451,6 +531,7 @@ static int logical_render_ring_init(struct drm_device *dev) ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; + ring->emit_flush = gen8_emit_flush_render; return logical_ring_init(dev, ring); } @@ -470,6 +551,7 @@ static int logical_bsd_ring_init(struct drm_device *dev) ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; + ring->emit_flush = gen8_emit_flush; return logical_ring_init(dev, ring); } @@ -489,6 +571,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev) ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; + ring->emit_flush = gen8_emit_flush; return logical_ring_init(dev, ring); } @@ -508,6 +591,7 @@ static int logical_blt_ring_init(struct drm_device *dev) ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; + ring->emit_flush = gen8_emit_flush; return logical_ring_init(dev, ring); } @@ -527,6 +611,7 @@ static int logical_vebox_ring_init(struct drm_device *dev) ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; + ring->emit_flush = gen8_emit_flush; return logical_ring_init(dev, ring); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 0bfa018fab20..4236014c1cda 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -33,13 +33,6 @@ #include "i915_trace.h" #include "intel_drv.h" -/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill, - * but keeps the logic simple. Indeed, the whole purpose of this macro is just - * to give some inclination as to some of the magic values used in the various - * workarounds! - */ -#define CACHELINE_BYTES 64 - bool intel_ring_initialized(struct intel_engine_cs *ring) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 467885159a80..e497837c7724 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -5,6 +5,13 @@ #define I915_CMD_HASH_ORDER 9 +/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill, + * but keeps the logic simple. Indeed, the whole purpose of this macro is just + * to give some inclination as to some of the magic values used in the various + * workarounds! + */ +#define CACHELINE_BYTES 64 + /* * Gen2 BSpec "1. Programming Environment" / 1.4.4.6 "Ring Buffer Use" * Gen3 BSpec "vol1c Memory Interface Functions" / 2.3.4.5 "Ring Buffer Use" @@ -218,6 +225,9 @@ struct intel_engine_cs { /* Execlists */ int (*emit_request)(struct intel_ringbuffer *ringbuf); + int (*emit_flush)(struct intel_ringbuffer *ringbuf, + u32 invalidate_domains, + u32 flush_domains); /** * List of objects currently involved in rendering from the -- GitLab From 9832b9dae8f9f505c7ed898a043b4f54b54597ed Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:30 +0100 Subject: [PATCH 0150/5088] drm/i915/bdw: Ring idle and stop with logical rings This is a hard one, since there is no direct hardware ring to control when in Execlists. We reuse intel_ring_idle here, but it should be fine as long as i915_add_request does the ring thing. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a88fa6e9360b..8a524baa8a6b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -105,7 +105,24 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, void intel_logical_ring_stop(struct intel_engine_cs *ring) { - /* TODO */ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + int ret; + + if (!intel_ring_initialized(ring)) + return; + + ret = intel_ring_idle(ring); + if (ret && !i915_reset_in_progress(&to_i915(ring->dev)->gpu_error)) + DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n", + ring->name, ret); + + /* TODO: Is this correct with Execlists enabled? */ + I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING)); + if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) { + DRM_ERROR("%s :timed out trying to stop ring\n", ring->name); + return; + } + I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING)); } void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf) @@ -458,10 +475,13 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf) void intel_logical_ring_cleanup(struct intel_engine_cs *ring) { + struct drm_i915_private *dev_priv = ring->dev->dev_private; + if (!intel_ring_initialized(ring)) return; - /* TODO: make sure the ring is stopped */ + intel_logical_ring_stop(ring); + WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0); ring->preallocated_lazy_request = NULL; ring->outstanding_lazy_seqno = 0; -- GitLab From 73d477f6bb17a1f14c4897a4b4a6597fe9a38ad2 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:31 +0100 Subject: [PATCH 0151/5088] drm/i915/bdw: Interrupts with logical rings We need to attend context switch interrupts from all rings. Also, fixed writing IMR/IER and added HWSTAM at ring init time. Notice that, if added to irq_enable_mask, the context switch interrupts would be incorrectly masked out when the user interrupts are due to no users waiting on a sequence number. Therefore, this commit adds a bitmask of interrupts to be kept unmasked at all times. v2: Disable HWSTAM, as suggested by Damien (nobody listens to these interrupts, anyway). v3: Add new get/put_irq functions. Signed-off-by: Thomas Daniel (v1) Signed-off-by: Oscar Mateo (v2 & v3) Reviewed-by: Damien Lespiau [danvet: Drop the GEN8_ prefix from the context switch interrupt define and move it to its brethren.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 19 ++++++-- drivers/gpu/drm/i915/i915_reg.h | 2 + drivers/gpu/drm/i915/intel_lrc.c | 58 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 36eb1f234608..00957fa0b877 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1647,6 +1647,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, notify_ring(dev, &dev_priv->ring[RCS]); if (bcs & GT_RENDER_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[BCS]); + if ((rcs | bcs) & GT_CONTEXT_SWITCH_INTERRUPT) + DRM_DEBUG_DRIVER("TODO: Context switch\n"); } else DRM_ERROR("The master control interrupt lied (GT0)!\n"); } @@ -1659,9 +1661,13 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, vcs = tmp >> GEN8_VCS1_IRQ_SHIFT; if (vcs & GT_RENDER_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[VCS]); + if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) + DRM_DEBUG_DRIVER("TODO: Context switch\n"); vcs = tmp >> GEN8_VCS2_IRQ_SHIFT; if (vcs & GT_RENDER_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[VCS2]); + if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) + DRM_DEBUG_DRIVER("TODO: Context switch\n"); } else DRM_ERROR("The master control interrupt lied (GT1)!\n"); } @@ -1685,6 +1691,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, vcs = tmp >> GEN8_VECS_IRQ_SHIFT; if (vcs & GT_RENDER_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[VECS]); + if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) + DRM_DEBUG_DRIVER("TODO: Context switch\n"); } else DRM_ERROR("The master control interrupt lied (GT3)!\n"); } @@ -3788,12 +3796,17 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) /* These are interrupts we'll toggle with the ring mask register */ uint32_t gt_interrupts[] = { GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT | GT_RENDER_L3_PARITY_ERROR_INTERRUPT | - GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT, + GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT | + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT, GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT | - GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT, + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT | + GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT | + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT, 0, - GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT + GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT | + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT }; for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3388afb90a93..f79c20d49d99 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1087,6 +1087,7 @@ enum punit_power_well { #define RING_ACTHD_UDW(base) ((base)+0x5c) #define RING_NOPID(base) ((base)+0x94) #define RING_IMR(base) ((base)+0xa8) +#define RING_HWSTAM(base) ((base)+0x98) #define RING_TIMESTAMP(base) ((base)+0x358) #define TAIL_ADDR 0x001FFFF8 #define HEAD_WRAP_COUNT 0xFFE00000 @@ -1403,6 +1404,7 @@ enum punit_power_well { #define GT_BSD_CS_ERROR_INTERRUPT (1 << 15) #define GT_BSD_USER_INTERRUPT (1 << 12) #define GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1 (1 << 11) /* hsw+; rsvd on snb, ivb, vlv */ +#define GT_CONTEXT_SWITCH_INTERRUPT (1 << 8) #define GT_RENDER_L3_PARITY_ERROR_INTERRUPT (1 << 5) /* !snb */ #define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT (1 << 4) #define GT_RENDER_CS_MASTER_ERROR_INTERRUPT (1 << 3) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8a524baa8a6b..009a8b5c088e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -319,6 +319,9 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask)); + I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff); + I915_WRITE(RING_MODE_GEN7(ring), _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); @@ -357,6 +360,39 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring) return ret; } +static bool gen8_logical_ring_get_irq(struct intel_engine_cs *ring) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + if (!dev->irq_enabled) + return false; + + spin_lock_irqsave(&dev_priv->irq_lock, flags); + if (ring->irq_refcount++ == 0) { + I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask)); + POSTING_READ(RING_IMR(ring->mmio_base)); + } + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); + + return true; +} + +static void gen8_logical_ring_put_irq(struct intel_engine_cs *ring) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->irq_lock, flags); + if (--ring->irq_refcount == 0) { + I915_WRITE_IMR(ring, ~ring->irq_keep_mask); + POSTING_READ(RING_IMR(ring->mmio_base)); + } + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); +} + static int gen8_emit_flush(struct intel_ringbuffer *ringbuf, u32 invalidate_domains, u32 unused) @@ -545,6 +581,10 @@ static int logical_render_ring_init(struct drm_device *dev) ring->mmio_base = RENDER_RING_BASE; ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT; + ring->irq_keep_mask = + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT; + if (HAS_L3_DPF(dev)) + ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; ring->init = gen8_init_render_ring; ring->cleanup = intel_fini_pipe_control; @@ -552,6 +592,8 @@ static int logical_render_ring_init(struct drm_device *dev) ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; ring->emit_flush = gen8_emit_flush_render; + ring->irq_get = gen8_logical_ring_get_irq; + ring->irq_put = gen8_logical_ring_put_irq; return logical_ring_init(dev, ring); } @@ -566,12 +608,16 @@ static int logical_bsd_ring_init(struct drm_device *dev) ring->mmio_base = GEN6_BSD_RING_BASE; ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT; + ring->irq_keep_mask = + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT; ring->init = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; ring->emit_flush = gen8_emit_flush; + ring->irq_get = gen8_logical_ring_get_irq; + ring->irq_put = gen8_logical_ring_put_irq; return logical_ring_init(dev, ring); } @@ -586,12 +632,16 @@ static int logical_bsd2_ring_init(struct drm_device *dev) ring->mmio_base = GEN8_BSD2_RING_BASE; ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT; + ring->irq_keep_mask = + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT; ring->init = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; ring->emit_flush = gen8_emit_flush; + ring->irq_get = gen8_logical_ring_get_irq; + ring->irq_put = gen8_logical_ring_put_irq; return logical_ring_init(dev, ring); } @@ -606,12 +656,16 @@ static int logical_blt_ring_init(struct drm_device *dev) ring->mmio_base = BLT_RING_BASE; ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT; + ring->irq_keep_mask = + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT; ring->init = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; ring->emit_flush = gen8_emit_flush; + ring->irq_get = gen8_logical_ring_get_irq; + ring->irq_put = gen8_logical_ring_put_irq; return logical_ring_init(dev, ring); } @@ -626,12 +680,16 @@ static int logical_vebox_ring_init(struct drm_device *dev) ring->mmio_base = VEBOX_RING_BASE; ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT; + ring->irq_keep_mask = + GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT; ring->init = gen8_init_common_ring; ring->get_seqno = gen8_get_seqno; ring->set_seqno = gen8_set_seqno; ring->emit_request = gen8_emit_request; ring->emit_flush = gen8_emit_flush; + ring->irq_get = gen8_logical_ring_get_irq; + ring->irq_put = gen8_logical_ring_put_irq; return logical_ring_init(dev, ring); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index e497837c7724..cb529ee10c8f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -224,6 +224,7 @@ struct intel_engine_cs { } semaphore; /* Execlists */ + u32 irq_keep_mask; /* bitmask for interrupts that should not be masked */ int (*emit_request)(struct intel_ringbuffer *ringbuf); int (*emit_flush)(struct intel_ringbuffer *ringbuf, u32 invalidate_domains, -- GitLab From 156485852684b511be28a83c78fece8b27ef7c26 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:32 +0100 Subject: [PATCH 0152/5088] drm/i915/bdw: GEN-specific logical ring emit batchbuffer start Dispatch_execbuffer's evil twin. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Ditch the check for aliasing ppgtt. It'll break soon and execlists requires full ppgtt anyway.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 27 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 009a8b5c088e..e0d4ef2a5c30 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -360,6 +360,28 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring) return ret; } +static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf, + u64 offset, unsigned flags) +{ + struct intel_engine_cs *ring = ringbuf->ring; + struct drm_i915_private *dev_priv = ring->dev->dev_private; + bool ppgtt = !(flags & I915_DISPATCH_SECURE); + int ret; + + ret = intel_logical_ring_begin(ringbuf, 4); + if (ret) + 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, lower_32_bits(offset)); + intel_logical_ring_emit(ringbuf, upper_32_bits(offset)); + intel_logical_ring_emit(ringbuf, MI_NOOP); + intel_logical_ring_advance(ringbuf); + + return 0; +} + static bool gen8_logical_ring_get_irq(struct intel_engine_cs *ring) { struct drm_device *dev = ring->dev; @@ -594,6 +616,7 @@ static int logical_render_ring_init(struct drm_device *dev) ring->emit_flush = gen8_emit_flush_render; ring->irq_get = gen8_logical_ring_get_irq; ring->irq_put = gen8_logical_ring_put_irq; + ring->emit_bb_start = gen8_emit_bb_start; return logical_ring_init(dev, ring); } @@ -618,6 +641,7 @@ static int logical_bsd_ring_init(struct drm_device *dev) ring->emit_flush = gen8_emit_flush; ring->irq_get = gen8_logical_ring_get_irq; ring->irq_put = gen8_logical_ring_put_irq; + ring->emit_bb_start = gen8_emit_bb_start; return logical_ring_init(dev, ring); } @@ -642,6 +666,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev) ring->emit_flush = gen8_emit_flush; ring->irq_get = gen8_logical_ring_get_irq; ring->irq_put = gen8_logical_ring_put_irq; + ring->emit_bb_start = gen8_emit_bb_start; return logical_ring_init(dev, ring); } @@ -666,6 +691,7 @@ static int logical_blt_ring_init(struct drm_device *dev) ring->emit_flush = gen8_emit_flush; ring->irq_get = gen8_logical_ring_get_irq; ring->irq_put = gen8_logical_ring_put_irq; + ring->emit_bb_start = gen8_emit_bb_start; return logical_ring_init(dev, ring); } @@ -690,6 +716,7 @@ static int logical_vebox_ring_init(struct drm_device *dev) ring->emit_flush = gen8_emit_flush; ring->irq_get = gen8_logical_ring_get_irq; ring->irq_put = gen8_logical_ring_put_irq; + ring->emit_bb_start = gen8_emit_bb_start; return logical_ring_init(dev, ring); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index cb529ee10c8f..24437da91f77 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -229,6 +229,8 @@ struct intel_engine_cs { int (*emit_flush)(struct intel_ringbuffer *ringbuf, u32 invalidate_domains, u32 flush_domains); + int (*emit_bb_start)(struct intel_ringbuffer *ringbuf, + u64 offset, unsigned flags); /** * List of objects currently involved in rendering from the -- GitLab From ba8b7ccb196b07c1c553450e8e7b44a7a938e58a Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:33 +0100 Subject: [PATCH 0153/5088] drm/i915/bdw: Workload submission mechanism for Execlists This is what i915_gem_do_execbuffer calls when it wants to execute some worload in an Execlists world. v2: Check arguments before doing stuff in intel_execlists_submission. Also, get rel_constants parsing right. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Drop the chipset flush, that's pre-gen6. And appease checkpatch a bit .... again!] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 + drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 +- drivers/gpu/drm/i915/intel_lrc.c | 130 ++++++++++++++++++++- 3 files changed, 135 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9198f1c96470..53cc4c083d0d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2266,6 +2266,12 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 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); int i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, struct intel_engine_cs *ring, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 26b38b3ae4f3..7e04a4825ed0 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -942,7 +942,7 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, return ctx; } -static void +void i915_gem_execbuffer_move_to_active(struct list_head *vmas, struct intel_engine_cs *ring) { @@ -983,7 +983,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, } } -static void +void i915_gem_execbuffer_retire_commands(struct drm_device *dev, struct drm_file *file, struct intel_engine_cs *ring, diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index e0d4ef2a5c30..e1a298f23f50 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -91,6 +91,55 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists return 0; } +static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf) +{ + struct intel_engine_cs *ring = ringbuf->ring; + uint32_t flush_domains; + int ret; + + flush_domains = 0; + if (ring->gpu_caches_dirty) + flush_domains = I915_GEM_GPU_DOMAINS; + + ret = ring->emit_flush(ringbuf, I915_GEM_GPU_DOMAINS, flush_domains); + if (ret) + return ret; + + ring->gpu_caches_dirty = false; + return 0; +} + +static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf, + struct list_head *vmas) +{ + struct intel_engine_cs *ring = ringbuf->ring; + struct i915_vma *vma; + uint32_t flush_domains = 0; + bool flush_chipset = false; + int ret; + + list_for_each_entry(vma, vmas, exec_list) { + struct drm_i915_gem_object *obj = vma->obj; + + ret = i915_gem_object_sync(obj, ring); + if (ret) + return ret; + + if (obj->base.write_domain & I915_GEM_DOMAIN_CPU) + flush_chipset |= i915_gem_clflush_object(obj, false); + + flush_domains |= obj->base.write_domain; + } + + if (flush_domains & I915_GEM_DOMAIN_GTT) + wmb(); + + /* Unconditionally invalidate gpu caches and ensure that we do flush + * any residual writes from the previous batch. + */ + return logical_ring_invalidate_all_caches(ringbuf); +} + int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, struct intel_engine_cs *ring, struct intel_context *ctx, @@ -99,7 +148,84 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, struct drm_i915_gem_object *batch_obj, u64 exec_start, u32 flags) { - /* TODO */ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; + int instp_mode; + u32 instp_mask; + int ret; + + instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK; + instp_mask = I915_EXEC_CONSTANTS_MASK; + switch (instp_mode) { + case I915_EXEC_CONSTANTS_REL_GENERAL: + case I915_EXEC_CONSTANTS_ABSOLUTE: + case I915_EXEC_CONSTANTS_REL_SURFACE: + if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) { + DRM_DEBUG("non-0 rel constants mode on non-RCS\n"); + return -EINVAL; + } + + if (instp_mode != dev_priv->relative_constants_mode) { + if (instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) { + DRM_DEBUG("rel surface constants mode invalid on gen5+\n"); + return -EINVAL; + } + + /* The HW changed the meaning on this bit on gen6 */ + instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE; + } + break; + default: + DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode); + return -EINVAL; + } + + if (args->num_cliprects != 0) { + DRM_DEBUG("clip rectangles are only valid on pre-gen5\n"); + return -EINVAL; + } else { + if (args->DR4 == 0xffffffff) { + DRM_DEBUG("UXA submitting garbage DR4, fixing up\n"); + args->DR4 = 0; + } + + if (args->DR1 || args->DR4 || args->cliprects_ptr) { + DRM_DEBUG("0 cliprects but dirt in cliprects fields\n"); + return -EINVAL; + } + } + + if (args->flags & I915_EXEC_GEN7_SOL_RESET) { + DRM_DEBUG("sol reset is gen7 only\n"); + return -EINVAL; + } + + ret = execlists_move_to_gpu(ringbuf, vmas); + if (ret) + return ret; + + if (ring == &dev_priv->ring[RCS] && + instp_mode != dev_priv->relative_constants_mode) { + ret = intel_logical_ring_begin(ringbuf, 4); + if (ret) + return ret; + + intel_logical_ring_emit(ringbuf, MI_NOOP); + intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(1)); + intel_logical_ring_emit(ringbuf, INSTPM); + intel_logical_ring_emit(ringbuf, instp_mask << 16 | instp_mode); + intel_logical_ring_advance(ringbuf); + + dev_priv->relative_constants_mode = instp_mode; + } + + ret = ring->emit_bb_start(ringbuf, exec_start, flags); + if (ret) + return ret; + + i915_gem_execbuffer_move_to_active(vmas, ring); + i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); + return 0; } @@ -363,8 +489,6 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring) static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf, u64 offset, unsigned flags) { - struct intel_engine_cs *ring = ringbuf->ring; - struct drm_i915_private *dev_priv = ring->dev->dev_private; bool ppgtt = !(flags & I915_DISPATCH_SECURE); int ret; -- GitLab From 14bf993e83e1d6924f4bf4506120a15c4b255e58 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:34 +0100 Subject: [PATCH 0154/5088] drm/i915/bdw: Always use MMIO flips with Execlists The normal flip function places things in the ring in the legacy way, so we either fix that or force MMIO flips always as we do in this patch. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Checkpatch. Fucking again.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 ++ drivers/gpu/drm/i915/intel_lrc.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 245cf4128314..1bd1aa21a8e9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9536,6 +9536,8 @@ static bool use_mmio_flip(struct intel_engine_cs *ring, return false; else if (i915.use_mmio_flip > 0) return true; + else if (i915.enable_execlists) + return true; else return ring != obj->ring; } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index e1a298f23f50..6f1b64e01a05 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -85,7 +85,8 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists if (enable_execlists == 0) return 0; - if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev)) + if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev) && + i915.use_mmio_flip >= 0) return 1; return 0; -- GitLab From 743cb1ff191f00fee653212bdbcee1e56086d6ce Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 29 Jul 2014 17:00:21 +0200 Subject: [PATCH 0155/5088] sched/fair: Make calculate_imbalance() independent Rik noticed that calculate_imbalance() relies on update_sd_pick_busiest() to guarantee that busiest->sum_nr_running > busiest->group_capacity_factor. Break this implicit assumption (with the intent of not providing it anymore) by having calculat_imbalance() verify it and not rely on others. Reported-by: Rik van Riel Signed-off-by: Peter Zijlstra Acked-by: Vincent Guittot Cc: Linus Torvalds Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/20140729152631.GW12054@laptop.lan Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index bfa3c86d0d68..e9477e6193fc 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6248,7 +6248,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s return fix_small_imbalance(env, sds); } - if (!busiest->group_imb) { + if (busiest->sum_nr_running > busiest->group_capacity_factor) { /* * Don't want to pull so many tasks that a group would go idle. * Except of course for the group_imb case, since then we might -- GitLab From caeb178c60f4f93f1b45c0bc056b5cf6d217b67f Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Mon, 28 Jul 2014 14:16:28 -0400 Subject: [PATCH 0156/5088] sched/fair: Make update_sd_pick_busiest() return 'true' on a busier sd Currently update_sd_pick_busiest only identifies the busiest sd that is either overloaded, or has a group imbalance. When no sd is imbalanced or overloaded, the load balancer fails to find the busiest domain. This breaks load balancing between domains that are not overloaded, in the !SD_ASYM_PACKING case. This patch makes update_sd_pick_busiest return true when the busiest sd yet is encountered. Groups are ranked in the order overloaded > imbalanced > other, with higher ranked groups getting priority even when their load is lower. This is necessary due to the possibility of unequal capacities and cpumasks between domains within a sched group. Behaviour for SD_ASYM_PACKING does not seem to match the comment, but I have no hardware to test that so I have left the behaviour of that code unchanged. Enum for group classification suggested by Peter Zijlstra. Signed-off-by: Rik van Riel [peterz: replaced sg_lb_stats::group_imb with the new enum group_type in an attempt to avoid endless recalculation] Signed-off-by: Peter Zijlstra Acked-by: Vincent Guittot Acked-by: Michael Neuling Cc: ktkhai@parallels.com Cc: tim.c.chen@linux.intel.com Cc: nicolas.pitre@linaro.org Cc: jhladky@redhat.com Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20140729152743.GI3935@laptop Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 49 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index e9477e6193fc..94377254254e 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5559,6 +5559,13 @@ static unsigned long task_h_load(struct task_struct *p) #endif /********** Helpers for find_busiest_group ************************/ + +enum group_type { + group_other = 0, + group_imbalanced, + group_overloaded, +}; + /* * sg_lb_stats - stats of a sched_group required for load_balancing */ @@ -5572,7 +5579,7 @@ struct sg_lb_stats { unsigned int group_capacity_factor; unsigned int idle_cpus; unsigned int group_weight; - int group_imb; /* Is there an imbalance in the group ? */ + enum group_type group_type; int group_has_free_capacity; #ifdef CONFIG_NUMA_BALANCING unsigned int nr_numa_running; @@ -5610,6 +5617,8 @@ static inline void init_sd_lb_stats(struct sd_lb_stats *sds) .total_capacity = 0UL, .busiest_stat = { .avg_load = 0UL, + .sum_nr_running = 0, + .group_type = group_other, }, }; } @@ -5891,6 +5900,18 @@ static inline int sg_capacity_factor(struct lb_env *env, struct sched_group *gro return capacity_factor; } +static enum group_type +group_classify(struct sched_group *group, struct sg_lb_stats *sgs) +{ + if (sgs->sum_nr_running > sgs->group_capacity_factor) + return group_overloaded; + + if (sg_imbalanced(group)) + return group_imbalanced; + + return group_other; +} + /** * update_sg_lb_stats - Update sched_group's statistics for load balancing. * @env: The load balancing environment. @@ -5942,9 +5963,8 @@ static inline void update_sg_lb_stats(struct lb_env *env, sgs->load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running; sgs->group_weight = group->group_weight; - - sgs->group_imb = sg_imbalanced(group); sgs->group_capacity_factor = sg_capacity_factor(env, group); + sgs->group_type = group_classify(group, sgs); if (sgs->group_capacity_factor > sgs->sum_nr_running) sgs->group_has_free_capacity = 1; @@ -5968,13 +5988,19 @@ static bool update_sd_pick_busiest(struct lb_env *env, struct sched_group *sg, struct sg_lb_stats *sgs) { - if (sgs->avg_load <= sds->busiest_stat.avg_load) - return false; + struct sg_lb_stats *busiest = &sds->busiest_stat; - if (sgs->sum_nr_running > sgs->group_capacity_factor) + if (sgs->group_type > busiest->group_type) return true; - if (sgs->group_imb) + if (sgs->group_type < busiest->group_type) + return false; + + if (sgs->avg_load <= busiest->avg_load) + return false; + + /* This is the busiest node in its class. */ + if (!(env->sd->flags & SD_ASYM_PACKING)) return true; /* @@ -5982,8 +6008,7 @@ static bool update_sd_pick_busiest(struct lb_env *env, * numbered CPUs in the group, therefore mark all groups * higher than ourself as busy. */ - if ((env->sd->flags & SD_ASYM_PACKING) && sgs->sum_nr_running && - env->dst_cpu < group_first_cpu(sg)) { + if (sgs->sum_nr_running && env->dst_cpu < group_first_cpu(sg)) { if (!sds->busiest) return true; @@ -6228,7 +6253,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s local = &sds->local_stat; busiest = &sds->busiest_stat; - if (busiest->group_imb) { + if (busiest->group_type == group_imbalanced) { /* * In the group_imb case we cannot rely on group-wide averages * to ensure cpu-load equilibrium, look at wider averages. XXX @@ -6248,7 +6273,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s return fix_small_imbalance(env, sds); } - if (busiest->sum_nr_running > busiest->group_capacity_factor) { + if (busiest->group_type == group_overloaded) { /* * Don't want to pull so many tasks that a group would go idle. * Except of course for the group_imb case, since then we might @@ -6337,7 +6362,7 @@ static struct sched_group *find_busiest_group(struct lb_env *env) * work because they assume all things are equal, which typically * isn't true due to cpus_allowed constraints and the like. */ - if (busiest->group_imb) + if (busiest->group_type == group_imbalanced) goto force_balance; /* SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */ -- GitLab From 9a5d9ba6a3631d55c358fe1bdbaa162a97471a05 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 29 Jul 2014 17:15:11 +0200 Subject: [PATCH 0157/5088] sched/fair: Allow calculate_imbalance() to move idle cpus Allow calculate_imbalance() to 'create' idle cpus in the busiest group if there are idle cpus in the local group. Suggested-by: Rik van Riel Signed-off-by: Peter Zijlstra Acked-by: Vincent Guittot Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20140729152705.GX12054@laptop.lan Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 94377254254e..df1ed176c7b7 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6273,12 +6273,11 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s return fix_small_imbalance(env, sds); } - if (busiest->group_type == group_overloaded) { - /* - * Don't want to pull so many tasks that a group would go idle. - * Except of course for the group_imb case, since then we might - * have to drop below capacity to reach cpu-load equilibrium. - */ + /* + * If there aren't any idle cpus, avoid creating some. + */ + if (busiest->group_type == group_overloaded && + local->group_type == group_overloaded) { load_above_capacity = (busiest->sum_nr_running - busiest->group_capacity_factor); -- GitLab From aaecac4ad46b35ad308245384d019633fb9bc21b Mon Sep 17 00:00:00 2001 From: Zhihui Zhang Date: Fri, 1 Aug 2014 21:18:03 -0400 Subject: [PATCH 0158/5088] sched: Rename a misleading variable in build_overlap_sched_groups() The child variable in build_overlap_sched_groups() actually refers to the peer or sibling domain of the given CPU. Rename it to sibling to be consistent with the naming in build_group_mask(). Signed-off-by: Zhihui Zhang Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/1406942283-18249-1-git-send-email-zzhsuny@gmail.com Signed-off-by: Ingo Molnar --- kernel/sched/core.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1211575a2208..7d1ec6e60535 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5739,7 +5739,7 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu) const struct cpumask *span = sched_domain_span(sd); struct cpumask *covered = sched_domains_tmpmask; struct sd_data *sdd = sd->private; - struct sched_domain *child; + struct sched_domain *sibling; int i; cpumask_clear(covered); @@ -5750,10 +5750,10 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu) if (cpumask_test_cpu(i, covered)) continue; - child = *per_cpu_ptr(sdd->sd, i); + sibling = *per_cpu_ptr(sdd->sd, i); /* See the comment near build_group_mask(). */ - if (!cpumask_test_cpu(i, sched_domain_span(child))) + if (!cpumask_test_cpu(i, sched_domain_span(sibling))) continue; sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), @@ -5763,10 +5763,9 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu) goto fail; sg_span = sched_group_cpus(sg); - if (child->child) { - child = child->child; - cpumask_copy(sg_span, sched_domain_span(child)); - } else + if (sibling->child) + cpumask_copy(sg_span, sched_domain_span(sibling->child)); + else cpumask_set_cpu(i, sg_span); cpumask_or(covered, covered, sg_span); -- GitLab From b932c03c34f3b03c7364c06aa8cae5b74609fc41 Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Mon, 4 Aug 2014 13:23:27 -0400 Subject: [PATCH 0159/5088] sched/numa: Fix off-by-one in capacity check Commit a43455a1d572daf7b730fe12eb747d1e17411365 ensures that task_numa_migrate will call task_numa_compare on the preferred node all the time, even when the preferred node has no free capacity. This could lead to a performance regression if nr_running == capacity on both the source and the destination node. This can be avoided by also checking for nr_running == capacity on the source node, which is one stricter than checking .has_free_capacity. Signed-off-by: Rik van Riel Signed-off-by: Peter Zijlstra Cc: mgorman@suse.de Cc: vincent.guittot@linaro.org Cc: Morten.Rasmussen@arm.com Cc: nicolas.pitre@linaro.org Cc: efault@gmx.de Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1407173008-9334-2-git-send-email-riel@redhat.com Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index df1ed176c7b7..e1cf419c3c7f 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -1206,7 +1206,7 @@ static void task_numa_compare(struct task_numa_env *env, if (!cur) { /* Is there capacity at our destination? */ - if (env->src_stats.has_free_capacity && + if (env->src_stats.nr_running <= env->src_stats.task_capacity && !env->dst_stats.has_free_capacity) goto unlock; -- GitLab From 83d7f2424741c9dc76c21377c9d00d47abaf88df Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Mon, 4 Aug 2014 13:23:28 -0400 Subject: [PATCH 0160/5088] sched/numa: Fix numa capacity computation Commit c61037e9 fixes the phenomenon of 'fantom' cores due to N*frac(smt_power) >= 1 by limiting the capacity to the actual number of cores in the load balancing code. This patch applies the same correction to the NUMA balancing code. Signed-off-by: Rik van Riel Signed-off-by: Peter Zijlstra Cc: mgorman@suse.de Cc: vincent.guittot@linaro.org Cc: Morten.Rasmussen@arm.com Cc: nicolas.pitre@linaro.org Cc: efault@gmx.de Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1407173008-9334-3-git-send-email-riel@redhat.com Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index e1cf419c3c7f..1413c44ce8a1 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -1038,7 +1038,8 @@ struct numa_stats { */ static void update_numa_stats(struct numa_stats *ns, int nid) { - int cpu, cpus = 0; + int smt, cpu, cpus = 0; + unsigned long capacity; memset(ns, 0, sizeof(*ns)); for_each_cpu(cpu, cpumask_of_node(nid)) { @@ -1062,8 +1063,12 @@ static void update_numa_stats(struct numa_stats *ns, int nid) if (!cpus) return; - ns->task_capacity = - DIV_ROUND_CLOSEST(ns->compute_capacity, SCHED_CAPACITY_SCALE); + /* smt := ceil(cpus / capacity), assumes: 1 < smt_power < 2 */ + smt = DIV_ROUND_UP(SCHED_CAPACITY_SCALE * cpus, ns->compute_capacity); + capacity = cpus / smt; /* cores */ + + ns->task_capacity = min_t(unsigned, capacity, + DIV_ROUND_CLOSEST(ns->compute_capacity, SCHED_CAPACITY_SCALE)); ns->has_free_capacity = (ns->nr_running < ns->task_capacity); } -- GitLab From b9d06dd9d1dd3672b391e6387d62aa8dc4e377bd Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Wed, 6 Aug 2014 15:04:44 +0200 Subject: [PATCH 0161/5088] drm/i915: vma/ppgtt lifetime rules VMAs should take a reference of the address space they use. Now, when the fd is closed, it will release the ref that the context was holding, but it will still be referenced by any vmas that are still active. ppgtt_release() should then only be called when the last thing referencing it releases the ref, and it can just call the base cleanup and free the ppgtt. Note that with this we will extend the lifetime of ppgtts which contain shared objects. But all the non-shared objects will get removed as soon as they drop of the active list and for the shared ones the shrinker can eventually reap them. Since we currently can't evict ppgtt pagetables either I don't think that temporary leak is important. Signed-off-by: Michel Thierry [danvet: Add note about potential ppgtt leak with this approach.] 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 | 23 +++-------------------- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 +++++ 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 53cc4c083d0d..38b1849a450a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2547,7 +2547,9 @@ void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj); /* i915_gem_context.c */ #define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base) +#define vm_to_ppgtt(vm) container_of(vm, struct i915_hw_ppgtt, base) int __must_check i915_gem_context_init(struct drm_device *dev); +void ppgtt_release(struct kref *kref); 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); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9acb2469116a..63aee412b258 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4476,12 +4476,20 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, void i915_gem_vma_destroy(struct i915_vma *vma) { + struct i915_address_space *vm = NULL; + struct i915_hw_ppgtt *ppgtt = NULL; WARN_ON(vma->node.allocated); /* Keep the vma as a placeholder in the execbuffer reservation lists */ if (!list_empty(&vma->exec_list)) return; + vm = vma->vm; + ppgtt = vm_to_ppgtt(vm); + + if (ppgtt) + kref_put(&ppgtt->ref, ppgtt_release); + list_del(&vma->vma_link); kfree(vma); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 7a08f3e9e1ae..a509a4bca991 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -108,30 +108,13 @@ static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) return; } - /* - * Make sure vmas are unbound before we take down the drm_mm - * - * FIXME: Proper refcounting should take care of this, this shouldn't be - * needed at all. - */ - if (!list_empty(&vm->active_list)) { - struct i915_vma *vma; - - list_for_each_entry(vma, &vm->active_list, mm_list) - if (WARN_ON(list_empty(&vma->vma_link) || - list_is_singular(&vma->vma_link))) - break; - - i915_gem_evict_vm(&ppgtt->base, true); - } else { - i915_gem_retire_requests(dev); - i915_gem_evict_vm(&ppgtt->base, false); - } + /* vmas should already be unbound */ + WARN_ON(!list_empty(&vm->active_list)); ppgtt->base.cleanup(&ppgtt->base); } -static void ppgtt_release(struct kref *kref) +void ppgtt_release(struct kref *kref) { struct i915_hw_ppgtt *ppgtt = container_of(kref, struct i915_hw_ppgtt, ref); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b4b7cfd226b7..76dd3b428483 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2148,10 +2148,15 @@ i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, struct i915_address_space *vm) { struct i915_vma *vma; + struct i915_hw_ppgtt *ppgtt = NULL; vma = i915_gem_obj_to_vma(obj, vm); if (!vma) vma = __i915_gem_vma_create(obj, vm); + ppgtt = vm_to_ppgtt(vm); + if (ppgtt) + kref_get(&ppgtt->ref); + return vma; } -- GitLab From ee960be7bb09b201926cb37eaa82fb7da605ea7c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:45 +0200 Subject: [PATCH 0162/5088] drm/i915: Some cleanups for the ppgtt lifetime handling So when reviewing Michel's patch I've noticed a few things and cleaned them up: - The early checks in ppgtt_release are now redundant: The inactive list should always be empty now, so we can ditch these checks. Even for the aliasing ppgtt (though that's a different confusion) since we tear that down after all the objects are gone. - The ppgtt handling functions are splattered all over. Consolidate them in i915_gem_gtt.c, give them OCD prefixes and add wrappers for get/put. - There was a bit a confusion in ppgtt_release about whether it cares about the active or inactive list. It should care about them both, so augment the WARNINGs to check for both. There's still create_vm_for_ctx left to do, put that is blocked on the removal of ppgtt->ctx. Once that's done we can rename it to i915_ppgtt_create and move it to its siblings for handling ppgtts. v2: Move the ppgtt checks into the inline get/put functions as suggested by Chris. v3: Inline the now redundant ppgtt local variable. Cc: Michel Thierry Cc: Chris Wilson Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem.c | 5 +--- drivers/gpu/drm/i915/i915_gem_context.c | 36 +++---------------------- drivers/gpu/drm/i915/i915_gem_gtt.c | 20 ++++++++++---- drivers/gpu/drm/i915/i915_gem_gtt.h | 14 +++++++++- 5 files changed, 33 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 38b1849a450a..101fc637eb46 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2549,7 +2549,6 @@ void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj); #define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base) #define vm_to_ppgtt(vm) container_of(vm, struct i915_hw_ppgtt, base) int __must_check i915_gem_context_init(struct drm_device *dev); -void ppgtt_release(struct kref *kref); 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); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 63aee412b258..8061d45eaa80 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4477,7 +4477,6 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, void i915_gem_vma_destroy(struct i915_vma *vma) { struct i915_address_space *vm = NULL; - struct i915_hw_ppgtt *ppgtt = NULL; WARN_ON(vma->node.allocated); /* Keep the vma as a placeholder in the execbuffer reservation lists */ @@ -4485,10 +4484,8 @@ void i915_gem_vma_destroy(struct i915_vma *vma) return; vm = vma->vm; - ppgtt = vm_to_ppgtt(vm); - if (ppgtt) - kref_put(&ppgtt->ref, ppgtt_release); + i915_ppgtt_put(vm_to_ppgtt(vm)); list_del(&vma->vma_link); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a509a4bca991..dc43d0263a01 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -96,33 +96,6 @@ #define GEN6_CONTEXT_ALIGN (64<<10) #define GEN7_CONTEXT_ALIGN 4096 -static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) -{ - struct drm_device *dev = ppgtt->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_address_space *vm = &ppgtt->base; - - if (ppgtt == dev_priv->mm.aliasing_ppgtt || - (list_empty(&vm->active_list) && list_empty(&vm->inactive_list))) { - ppgtt->base.cleanup(&ppgtt->base); - return; - } - - /* vmas should already be unbound */ - WARN_ON(!list_empty(&vm->active_list)); - - ppgtt->base.cleanup(&ppgtt->base); -} - -void ppgtt_release(struct kref *kref) -{ - struct i915_hw_ppgtt *ppgtt = - container_of(kref, struct i915_hw_ppgtt, ref); - - do_ppgtt_cleanup(ppgtt); - kfree(ppgtt); -} - static size_t get_context_alignment(struct drm_device *dev) { if (IS_GEN6(dev)) @@ -174,8 +147,7 @@ void i915_gem_context_free(struct kref *ctx_ref) ppgtt = ctx_to_ppgtt(ctx); } - if (ppgtt) - kref_put(&ppgtt->ref, ppgtt_release); + i915_ppgtt_put(ppgtt); if (ctx->legacy_hw_ctx.rcs_state) drm_gem_object_unreference(&ctx->legacy_hw_ctx.rcs_state->base); list_del(&ctx->link); @@ -222,7 +194,7 @@ create_vm_for_ctx(struct drm_device *dev, struct intel_context *ctx) if (!ppgtt) return ERR_PTR(-ENOMEM); - ret = i915_gem_init_ppgtt(dev, ppgtt); + ret = i915_ppgtt_init(dev, ppgtt); if (ret) { kfree(ppgtt); return ERR_PTR(ret); @@ -234,7 +206,7 @@ create_vm_for_ctx(struct drm_device *dev, struct intel_context *ctx) static struct intel_context * __create_hw_context(struct drm_device *dev, - struct drm_i915_file_private *file_priv) + struct drm_i915_file_private *file_priv) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_context *ctx; @@ -342,7 +314,7 @@ i915_gem_create_context(struct drm_device *dev, /* For platforms which only have aliasing PPGTT, we fake the * address space and refcounting. */ ctx->vm = &dev_priv->mm.aliasing_ppgtt->base; - kref_get(&dev_priv->mm.aliasing_ppgtt->ref); + i915_ppgtt_get(dev_priv->mm.aliasing_ppgtt); } else ctx->vm = &dev_priv->gtt.base; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 76dd3b428483..6ffa12b72538 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1180,7 +1180,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) return 0; } -int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) +int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) { struct drm_i915_private *dev_priv = dev->dev_private; int ret = 0; @@ -1211,6 +1211,19 @@ int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) return ret; } +void i915_ppgtt_release(struct kref *kref) +{ + struct i915_hw_ppgtt *ppgtt = + container_of(kref, struct i915_hw_ppgtt, ref); + + /* vmas should already be unbound */ + WARN_ON(!list_empty(&ppgtt->base.active_list)); + WARN_ON(!list_empty(&ppgtt->base.inactive_list)); + + ppgtt->base.cleanup(&ppgtt->base); + kfree(ppgtt); +} + static void ppgtt_bind_vma(struct i915_vma *vma, enum i915_cache_level cache_level, @@ -2148,15 +2161,12 @@ i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, struct i915_address_space *vm) { struct i915_vma *vma; - struct i915_hw_ppgtt *ppgtt = NULL; vma = i915_gem_obj_to_vma(obj, vm); if (!vma) vma = __i915_gem_vma_create(obj, vm); - ppgtt = vm_to_ppgtt(vm); - if (ppgtt) - kref_get(&ppgtt->ref); + i915_ppgtt_get(vm_to_ppgtt(vm)); return vma; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 666c938a51e3..c6beb528f955 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -272,7 +272,19 @@ void i915_gem_init_global_gtt(struct drm_device *dev); void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, unsigned long mappable_end, unsigned long end); -int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); + +int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); +void i915_ppgtt_release(struct kref *kref); +static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt) +{ + if (ppgtt) + kref_get(&ppgtt->ref); +} +static inline void i915_ppgtt_put(struct i915_hw_ppgtt *ppgtt) +{ + if (ppgtt) + kref_put(&ppgtt->ref, i915_ppgtt_release); +} void i915_check_and_clear_faults(struct drm_device *dev); void i915_gem_suspend_gtt_mappings(struct drm_device *dev); -- GitLab From 8affc2b8c27bfc2d6e70827b746f490b62c44eaa Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 31 Jul 2014 14:45:04 +0800 Subject: [PATCH 0163/5088] perf record: Honour --no-time command line option Time stamps are always implicitely enabled for record currently. The old --time/-T option is a nop. Allow the user to disable timestamps by using --no-time, honouring the existing option. The defaults are unchanged. Signed-off-by: Andi Kleen Cc: Andi Kleen Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406789104-25863-10-git-send-email-zheng.z.yan@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 1 + tools/perf/util/evsel.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4869050e7194..ca0251e8470d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -781,6 +781,7 @@ static const char * const record_usage[] = { */ static struct record record = { .opts = { + .sample_time = true, .mmap_pages = UINT_MAX, .user_freq = UINT_MAX, .user_interval = ULLONG_MAX, diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 21a373ebea22..92e5235f5377 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -633,9 +633,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) if (opts->period) perf_evsel__set_sample_bit(evsel, PERIOD); - if (!perf_missing_features.sample_id_all && - (opts->sample_time || !opts->no_inherit || - target__has_cpu(&opts->target) || per_cpu)) + /* + * When the user explicitely disabled time don't force it here. + */ + if (opts->sample_time && + (!perf_missing_features.sample_id_all && + (!opts->no_inherit || target__has_cpu(&opts->target) || per_cpu))) perf_evsel__set_sample_bit(evsel, TIME); if (opts->raw_samples && !evsel->no_aux_samples) { -- GitLab From 0a8cb85c200c4082ed7e57efd90dd9d18c8d40b6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 6 Jul 2014 14:18:21 +0200 Subject: [PATCH 0164/5088] perf tools: Rename ordered_samples bool to ordered_events The time ordering is generic for all kinds of events, so using generic name 'ordered_events' for ordered_samples bool in perf_tool struct. No functional change was intended. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-07mrqzcuhsks9wfmxrzsvemz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-kvm.c | 4 ++-- tools/perf/builtin-lock.c | 2 +- tools/perf/builtin-mem.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-script.c | 2 +- tools/perf/builtin-timechart.c | 2 +- tools/perf/builtin-trace.c | 2 +- tools/perf/util/session.c | 10 +++++----- tools/perf/util/tool.h | 2 +- 14 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 1ec429fef2be..952b5ece6740 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -297,7 +297,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) .comm = perf_event__process_comm, .exit = perf_event__process_exit, .fork = perf_event__process_fork, - .ordered_samples = true, + .ordered_events = true, .ordering_requires_timestamps = true, }, }; diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 9a5a035cb426..c10cc44bae19 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -360,7 +360,7 @@ static struct perf_tool tool = { .exit = perf_event__process_exit, .fork = perf_event__process_fork, .lost = perf_event__process_lost, - .ordered_samples = true, + .ordered_events = true, .ordering_requires_timestamps = true, }; diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 9a02807387d6..ee875cca13b1 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -366,7 +366,7 @@ static int __cmd_inject(struct perf_inject *inject) } else if (inject->sched_stat) { struct perf_evsel *evsel; - inject->tool.ordered_samples = true; + inject->tool.ordered_events = true; evlist__for_each(session->evlist, evsel) { const char *name = perf_evsel__name(evsel); diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index bef3376bfaf3..b5721116713b 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -256,7 +256,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, static struct perf_tool perf_kmem = { .sample = process_sample_event, .comm = perf_event__process_comm, - .ordered_samples = true, + .ordered_events = true, }; static double fragmentation(unsigned long n_req, unsigned long n_alloc) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index fe92dfdeab46..a05f43592e0a 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1058,7 +1058,7 @@ static int read_events(struct perf_kvm_stat *kvm) struct perf_tool eops = { .sample = process_sample_event, .comm = perf_event__process_comm, - .ordered_samples = true, + .ordered_events = true, }; struct perf_data_file file = { .path = kvm->file_name, @@ -1311,7 +1311,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, kvm->tool.exit = perf_event__process_exit; kvm->tool.fork = perf_event__process_fork; kvm->tool.lost = process_lost_event; - kvm->tool.ordered_samples = true; + kvm->tool.ordered_events = true; perf_tool__fill_defaults(&kvm->tool); /* set defaults */ diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 6148afc995c6..c8122d323621 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -852,7 +852,7 @@ static int __cmd_report(bool display_info) struct perf_tool eops = { .sample = process_sample_event, .comm = perf_event__process_comm, - .ordered_samples = true, + .ordered_events = true, }; struct perf_data_file file = { .path = input_name, diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 4a1a6c94a5eb..80e57c84adef 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -194,7 +194,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) .lost = perf_event__process_lost, .fork = perf_event__process_fork, .build_id = perf_event__process_build_id, - .ordered_samples = true, + .ordered_events = true, }, .input_name = "perf.data", }; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 21d830bafff3..c72cc5a12144 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -578,7 +578,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) .attr = perf_event__process_attr, .tracing_data = perf_event__process_tracing_data, .build_id = perf_event__process_build_id, - .ordered_samples = true, + .ordered_events = true, .ordering_requires_timestamps = true, }, .max_stack = PERF_MAX_STACK_DEPTH, diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index f83c08c0dd87..7c16aeb6b675 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1662,7 +1662,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) .comm = perf_event__process_comm, .lost = perf_event__process_lost, .fork = perf_sched__process_fork_event, - .ordered_samples = true, + .ordered_events = true, }, .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), .sort_list = LIST_HEAD_INIT(sched.sort_list), diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index f57035b89c15..868c17d09762 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1488,7 +1488,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) .attr = process_attr, .tracing_data = perf_event__process_tracing_data, .build_id = perf_event__process_build_id, - .ordered_samples = true, + .ordered_events = true, .ordering_requires_timestamps = true, }, }; diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 2f1a5220c090..912e3b5bb22b 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1920,7 +1920,7 @@ int cmd_timechart(int argc, const char **argv, .fork = process_fork_event, .exit = process_exit_event, .sample = process_sample_event, - .ordered_samples = true, + .ordered_events = true, }, .proc_num = 15, .min_time = 1000000, diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index a6c375224f46..36ae51d61be2 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2209,7 +2209,7 @@ static int trace__replay(struct trace *trace) trace->tool.tracing_data = perf_event__process_tracing_data; trace->tool.build_id = perf_event__process_build_id; - trace->tool.ordered_samples = true; + trace->tool.ordered_events = true; trace->tool.ordering_requires_timestamps = true; /* add tid to output */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 88dfef70c13d..a2c97ff1aa6a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -104,9 +104,9 @@ struct perf_session *perf_session__new(struct perf_data_file *file, } if (tool && tool->ordering_requires_timestamps && - tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) { + tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) { dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); - tool->ordered_samples = false; + tool->ordered_events = false; } return session; @@ -238,7 +238,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool) if (tool->build_id == NULL) tool->build_id = process_finished_round_stub; if (tool->finished_round == NULL) { - if (tool->ordered_samples) + if (tool->ordered_events) tool->finished_round = process_finished_round; else tool->finished_round = process_finished_round_stub; @@ -483,7 +483,7 @@ static int flush_sample_queue(struct perf_session *s, struct ui_progress prog; int ret; - if (!tool->ordered_samples || !limit) + if (!tool->ordered_events || !limit) return 0; if (show_progress) @@ -1062,7 +1062,7 @@ static s64 perf_session__process_event(struct perf_session *session, if (ret) return ret; - if (tool->ordered_samples) { + if (tool->ordered_events) { ret = perf_session_queue_event(session, event, &sample, file_offset); if (ret != -ETIME) diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 4385816d3d49..f11636966a0f 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -40,7 +40,7 @@ struct perf_tool { event_op2 tracing_data; event_op2 finished_round, build_id; - bool ordered_samples; + bool ordered_events; bool ordering_requires_timestamps; }; -- GitLab From 37e39aa8a8a42ad2fd72b7c7349115dad8297d9c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 6 Jul 2014 14:23:03 +0200 Subject: [PATCH 0165/5088] perf tools: Rename ordered_samples struct to ordered_events Following up with ordered_samples rename for ordered_samples and sample_queue structs to ordered_events and ordered_event structs respectively. Also changing flush_sample_queue function name to ordered_events_flush. No functional change was intended. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-2dkrdvh0bbmzxdse437fcgls@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 2 +- tools/perf/util/session.c | 118 +++++++++++++++++++------------------- tools/perf/util/session.h | 10 ++-- 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index a05f43592e0a..258a5274099d 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -785,7 +785,7 @@ static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm) /* flush queue after each round in which we processed events */ if (ntotal) { - kvm->session->ordered_samples.next_flush = flush_time; + kvm->session->ordered_events.next_flush = flush_time; err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session); if (err) { if (kvm->lost_events) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index a2c97ff1aa6a..6570282a7625 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -75,9 +75,9 @@ struct perf_session *perf_session__new(struct perf_data_file *file, goto out; session->repipe = repipe; - INIT_LIST_HEAD(&session->ordered_samples.samples); - INIT_LIST_HEAD(&session->ordered_samples.sample_cache); - INIT_LIST_HEAD(&session->ordered_samples.to_free); + INIT_LIST_HEAD(&session->ordered_events.samples); + INIT_LIST_HEAD(&session->ordered_events.sample_cache); + INIT_LIST_HEAD(&session->ordered_events.to_free); machines__init(&session->machines); if (file) { @@ -444,7 +444,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_HEADER_MAX] = NULL, }; -struct sample_queue { +struct ordered_event { u64 timestamp; u64 file_offset; union perf_event *event; @@ -453,14 +453,14 @@ struct sample_queue { static void perf_session_free_sample_buffers(struct perf_session *session) { - struct ordered_samples *os = &session->ordered_samples; + struct ordered_events *oe = &session->ordered_events; - while (!list_empty(&os->to_free)) { - struct sample_queue *sq; + while (!list_empty(&oe->to_free)) { + struct ordered_event *event; - sq = list_entry(os->to_free.next, struct sample_queue, list); - list_del(&sq->list); - free(sq); + event = list_entry(oe->to_free.next, struct ordered_event, list); + list_del(&event->list); + free(event); } } @@ -470,15 +470,15 @@ static int perf_session_deliver_event(struct perf_session *session, struct perf_tool *tool, u64 file_offset); -static int flush_sample_queue(struct perf_session *s, - struct perf_tool *tool) +static int ordered_events__flush(struct perf_session *s, + struct perf_tool *tool) { - struct ordered_samples *os = &s->ordered_samples; - struct list_head *head = &os->samples; - struct sample_queue *tmp, *iter; + struct ordered_events *oe = &s->ordered_events; + struct list_head *head = &oe->samples; + struct ordered_event *tmp, *iter; struct perf_sample sample; - u64 limit = os->next_flush; - u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; + u64 limit = oe->next_flush; + u64 last_ts = oe->last_sample ? oe->last_sample->timestamp : 0ULL; bool show_progress = limit == ULLONG_MAX; struct ui_progress prog; int ret; @@ -487,7 +487,7 @@ static int flush_sample_queue(struct perf_session *s, return 0; if (show_progress) - ui_progress__init(&prog, os->nr_samples, "Processing time ordered events..."); + ui_progress__init(&prog, oe->nr_samples, "Processing time ordered events..."); list_for_each_entry_safe(iter, tmp, head, list) { if (session_done()) @@ -506,20 +506,20 @@ static int flush_sample_queue(struct perf_session *s, return ret; } - os->last_flush = iter->timestamp; + oe->last_flush = iter->timestamp; list_del(&iter->list); - list_add(&iter->list, &os->sample_cache); - os->nr_samples--; + list_add(&iter->list, &oe->sample_cache); + oe->nr_samples--; if (show_progress) ui_progress__update(&prog, 1); } if (list_empty(head)) { - os->last_sample = NULL; + oe->last_sample = NULL; } else if (last_ts <= limit) { - os->last_sample = - list_entry(head->prev, struct sample_queue, list); + oe->last_sample = + list_entry(head->prev, struct ordered_event, list); } return 0; @@ -568,27 +568,27 @@ static int process_finished_round(struct perf_tool *tool, union perf_event *event __maybe_unused, struct perf_session *session) { - int ret = flush_sample_queue(session, tool); + int ret = ordered_events__flush(session, tool); if (!ret) - session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; + session->ordered_events.next_flush = session->ordered_events.max_timestamp; return ret; } /* The queue is ordered by time */ -static void __queue_event(struct sample_queue *new, struct perf_session *s) +static void __queue_event(struct ordered_event *new, struct perf_session *s) { - struct ordered_samples *os = &s->ordered_samples; - struct sample_queue *sample = os->last_sample; + struct ordered_events *oe = &s->ordered_events; + struct ordered_event *sample = oe->last_sample; u64 timestamp = new->timestamp; struct list_head *p; - ++os->nr_samples; - os->last_sample = new; + ++oe->nr_samples; + oe->last_sample = new; if (!sample) { - list_add(&new->list, &os->samples); - os->max_timestamp = timestamp; + list_add(&new->list, &oe->samples); + oe->max_timestamp = timestamp; return; } @@ -600,59 +600,59 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s) if (sample->timestamp <= timestamp) { while (sample->timestamp <= timestamp) { p = sample->list.next; - if (p == &os->samples) { - list_add_tail(&new->list, &os->samples); - os->max_timestamp = timestamp; + if (p == &oe->samples) { + list_add_tail(&new->list, &oe->samples); + oe->max_timestamp = timestamp; return; } - sample = list_entry(p, struct sample_queue, list); + sample = list_entry(p, struct ordered_event, list); } list_add_tail(&new->list, &sample->list); } else { while (sample->timestamp > timestamp) { p = sample->list.prev; - if (p == &os->samples) { - list_add(&new->list, &os->samples); + if (p == &oe->samples) { + list_add(&new->list, &oe->samples); return; } - sample = list_entry(p, struct sample_queue, list); + sample = list_entry(p, struct ordered_event, list); } list_add(&new->list, &sample->list); } } -#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) +#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) int perf_session_queue_event(struct perf_session *s, union perf_event *event, struct perf_sample *sample, u64 file_offset) { - struct ordered_samples *os = &s->ordered_samples; - struct list_head *sc = &os->sample_cache; + struct ordered_events *oe = &s->ordered_events; + struct list_head *sc = &oe->sample_cache; u64 timestamp = sample->time; - struct sample_queue *new; + struct ordered_event *new; if (!timestamp || timestamp == ~0ULL) return -ETIME; - if (timestamp < s->ordered_samples.last_flush) { + if (timestamp < s->ordered_events.last_flush) { printf("Warning: Timestamp below last timeslice flush\n"); return -EINVAL; } if (!list_empty(sc)) { - new = list_entry(sc->next, struct sample_queue, list); + new = list_entry(sc->next, struct ordered_event, list); list_del(&new->list); - } else if (os->sample_buffer) { - new = os->sample_buffer + os->sample_buffer_idx; - if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER) - os->sample_buffer = NULL; + } else if (oe->sample_buffer) { + new = oe->sample_buffer + oe->sample_buffer_idx; + if (++oe->sample_buffer_idx == MAX_SAMPLE_BUFFER) + oe->sample_buffer = NULL; } else { - os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new)); - if (!os->sample_buffer) + oe->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new)); + if (!oe->sample_buffer) return -ENOMEM; - list_add(&os->sample_buffer->list, &os->to_free); - os->sample_buffer_idx = 2; - new = os->sample_buffer + 1; + list_add(&oe->sample_buffer->list, &oe->to_free); + oe->sample_buffer_idx = 2; + new = oe->sample_buffer + 1; } new->timestamp = timestamp; @@ -1222,8 +1222,8 @@ static int __perf_session__process_pipe_events(struct perf_session *session, goto more; done: /* do the final flush for ordered samples */ - session->ordered_samples.next_flush = ULLONG_MAX; - err = flush_sample_queue(session, tool); + session->ordered_events.next_flush = ULLONG_MAX; + err = ordered_events__flush(session, tool); out_err: free(buf); perf_session__warn_about_errors(session, tool); @@ -1368,8 +1368,8 @@ int __perf_session__process_events(struct perf_session *session, out: /* do the final flush for ordered samples */ - session->ordered_samples.next_flush = ULLONG_MAX; - err = flush_sample_queue(session, tool); + session->ordered_events.next_flush = ULLONG_MAX; + err = ordered_events__flush(session, tool); out_err: ui_progress__finish(); perf_session__warn_about_errors(session, tool); diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 0321013bd9fd..f6baf935917a 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -12,19 +12,19 @@ #include #include -struct sample_queue; +struct ordered_event; struct ip_callchain; struct thread; -struct ordered_samples { +struct ordered_events { u64 last_flush; u64 next_flush; u64 max_timestamp; struct list_head samples; struct list_head sample_cache; struct list_head to_free; - struct sample_queue *sample_buffer; - struct sample_queue *last_sample; + struct ordered_event *sample_buffer; + struct ordered_event *last_sample; int sample_buffer_idx; unsigned int nr_samples; }; @@ -39,7 +39,7 @@ struct perf_session { bool one_mmap; void *one_mmap_addr; u64 one_mmap_offset; - struct ordered_samples ordered_samples; + struct ordered_events ordered_events; struct perf_data_file *file; }; -- GitLab From fc12482f4f7ae5c6fca13922a1e0898ff9002aa6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 9 Jun 2014 23:11:30 +0200 Subject: [PATCH 0166/5088] perf tools: Rename ordered_events members Rename 'struct ordered_events' members to fit better the ordered events style. No functional change was intended. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-v0eb2hsmrxbolnoawu5fn92z@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 86 +++++++++++++++++++-------------------- tools/perf/util/session.h | 12 +++--- 2 files changed, 48 insertions(+), 50 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 6570282a7625..619778ef5b58 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -75,8 +75,8 @@ struct perf_session *perf_session__new(struct perf_data_file *file, goto out; session->repipe = repipe; - INIT_LIST_HEAD(&session->ordered_events.samples); - INIT_LIST_HEAD(&session->ordered_events.sample_cache); + INIT_LIST_HEAD(&session->ordered_events.events); + INIT_LIST_HEAD(&session->ordered_events.cache); INIT_LIST_HEAD(&session->ordered_events.to_free); machines__init(&session->machines); @@ -474,11 +474,11 @@ static int ordered_events__flush(struct perf_session *s, struct perf_tool *tool) { struct ordered_events *oe = &s->ordered_events; - struct list_head *head = &oe->samples; + struct list_head *head = &oe->events; struct ordered_event *tmp, *iter; struct perf_sample sample; u64 limit = oe->next_flush; - u64 last_ts = oe->last_sample ? oe->last_sample->timestamp : 0ULL; + u64 last_ts = oe->last ? oe->last->timestamp : 0ULL; bool show_progress = limit == ULLONG_MAX; struct ui_progress prog; int ret; @@ -487,7 +487,7 @@ static int ordered_events__flush(struct perf_session *s, return 0; if (show_progress) - ui_progress__init(&prog, oe->nr_samples, "Processing time ordered events..."); + ui_progress__init(&prog, oe->nr_events, "Processing time ordered events..."); list_for_each_entry_safe(iter, tmp, head, list) { if (session_done()) @@ -508,19 +508,17 @@ static int ordered_events__flush(struct perf_session *s, oe->last_flush = iter->timestamp; list_del(&iter->list); - list_add(&iter->list, &oe->sample_cache); - oe->nr_samples--; + list_add(&iter->list, &oe->cache); + oe->nr_events--; if (show_progress) ui_progress__update(&prog, 1); } - if (list_empty(head)) { - oe->last_sample = NULL; - } else if (last_ts <= limit) { - oe->last_sample = - list_entry(head->prev, struct ordered_event, list); - } + if (list_empty(head)) + oe->last = NULL; + else if (last_ts <= limit) + oe->last = list_entry(head->prev, struct ordered_event, list); return 0; } @@ -579,45 +577,45 @@ static int process_finished_round(struct perf_tool *tool, static void __queue_event(struct ordered_event *new, struct perf_session *s) { struct ordered_events *oe = &s->ordered_events; - struct ordered_event *sample = oe->last_sample; + struct ordered_event *last = oe->last; u64 timestamp = new->timestamp; struct list_head *p; - ++oe->nr_samples; - oe->last_sample = new; + ++oe->nr_events; + oe->last = new; - if (!sample) { - list_add(&new->list, &oe->samples); + if (!last) { + list_add(&new->list, &oe->events); oe->max_timestamp = timestamp; return; } /* - * last_sample might point to some random place in the list as it's + * last event might point to some random place in the list as it's * the last queued event. We expect that the new event is close to * this. */ - if (sample->timestamp <= timestamp) { - while (sample->timestamp <= timestamp) { - p = sample->list.next; - if (p == &oe->samples) { - list_add_tail(&new->list, &oe->samples); + if (last->timestamp <= timestamp) { + while (last->timestamp <= timestamp) { + p = last->list.next; + if (p == &oe->events) { + list_add_tail(&new->list, &oe->events); oe->max_timestamp = timestamp; return; } - sample = list_entry(p, struct ordered_event, list); + last = list_entry(p, struct ordered_event, list); } - list_add_tail(&new->list, &sample->list); + list_add_tail(&new->list, &last->list); } else { - while (sample->timestamp > timestamp) { - p = sample->list.prev; - if (p == &oe->samples) { - list_add(&new->list, &oe->samples); + while (last->timestamp > timestamp) { + p = last->list.prev; + if (p == &oe->events) { + list_add(&new->list, &oe->events); return; } - sample = list_entry(p, struct ordered_event, list); + last = list_entry(p, struct ordered_event, list); } - list_add(&new->list, &sample->list); + list_add(&new->list, &last->list); } } @@ -627,7 +625,7 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, struct perf_sample *sample, u64 file_offset) { struct ordered_events *oe = &s->ordered_events; - struct list_head *sc = &oe->sample_cache; + struct list_head *cache = &oe->cache; u64 timestamp = sample->time; struct ordered_event *new; @@ -639,20 +637,20 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, return -EINVAL; } - if (!list_empty(sc)) { - new = list_entry(sc->next, struct ordered_event, list); + if (!list_empty(cache)) { + new = list_entry(cache->next, struct ordered_event, list); list_del(&new->list); - } else if (oe->sample_buffer) { - new = oe->sample_buffer + oe->sample_buffer_idx; - if (++oe->sample_buffer_idx == MAX_SAMPLE_BUFFER) - oe->sample_buffer = NULL; + } else if (oe->buffer) { + new = oe->buffer + oe->buffer_idx; + if (++oe->buffer_idx == MAX_SAMPLE_BUFFER) + oe->buffer = NULL; } else { - oe->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new)); - if (!oe->sample_buffer) + oe->buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new)); + if (!oe->buffer) return -ENOMEM; - list_add(&oe->sample_buffer->list, &oe->to_free); - oe->sample_buffer_idx = 2; - new = oe->sample_buffer + 1; + list_add(&oe->buffer->list, &oe->to_free); + oe->buffer_idx = 2; + new = oe->buffer + 1; } new->timestamp = timestamp; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index f6baf935917a..419eb50e1cd3 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -20,13 +20,13 @@ struct ordered_events { u64 last_flush; u64 next_flush; u64 max_timestamp; - struct list_head samples; - struct list_head sample_cache; + struct list_head events; + struct list_head cache; struct list_head to_free; - struct ordered_event *sample_buffer; - struct ordered_event *last_sample; - int sample_buffer_idx; - unsigned int nr_samples; + struct ordered_event *buffer; + struct ordered_event *last; + int buffer_idx; + unsigned int nr_events; }; struct perf_session { -- GitLab From c64c7e1a5addf93b7dec98a27b8c48457506aa06 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 10 Jun 2014 21:58:02 +0200 Subject: [PATCH 0167/5088] perf tools: Add ordered_events__(new|delete) interface Adding new ordered events interface to new|delete event buffer: ordered_events__new - allocate event buffer from the cache ordered_events__delete - return event buffer to the cache Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-srwunsy7o5wl17vpt4a10oxp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 169 ++++++++++++++++++++++---------------- 1 file changed, 98 insertions(+), 71 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 619778ef5b58..ff0188c65783 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -464,6 +464,100 @@ static void perf_session_free_sample_buffers(struct perf_session *session) } } +/* The queue is ordered by time */ +static void queue_event(struct ordered_events *oe, struct ordered_event *new) +{ + struct ordered_event *last = oe->last; + u64 timestamp = new->timestamp; + struct list_head *p; + + ++oe->nr_events; + oe->last = new; + + if (!last) { + list_add(&new->list, &oe->events); + oe->max_timestamp = timestamp; + return; + } + + /* + * last event might point to some random place in the list as it's + * the last queued event. We expect that the new event is close to + * this. + */ + if (last->timestamp <= timestamp) { + while (last->timestamp <= timestamp) { + p = last->list.next; + if (p == &oe->events) { + list_add_tail(&new->list, &oe->events); + oe->max_timestamp = timestamp; + return; + } + last = list_entry(p, struct ordered_event, list); + } + list_add_tail(&new->list, &last->list); + } else { + while (last->timestamp > timestamp) { + p = last->list.prev; + if (p == &oe->events) { + list_add(&new->list, &oe->events); + return; + } + last = list_entry(p, struct ordered_event, list); + } + list_add(&new->list, &last->list); + } +} + +#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) +static struct ordered_event *alloc_event(struct ordered_events *oe) +{ + struct list_head *cache = &oe->cache; + struct ordered_event *new; + + if (!list_empty(cache)) { + new = list_entry(cache->next, struct ordered_event, list); + list_del(&new->list); + } else if (oe->buffer) { + new = oe->buffer + oe->buffer_idx; + if (++oe->buffer_idx == MAX_SAMPLE_BUFFER) + oe->buffer = NULL; + } else { + oe->buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new)); + if (!oe->buffer) + return NULL; + list_add(&oe->buffer->list, &oe->to_free); + + /* First entry is abused to maintain the to_free list. */ + oe->buffer_idx = 2; + new = oe->buffer + 1; + } + + return new; +} + +static struct ordered_event * +ordered_events__new(struct ordered_events *oe, u64 timestamp) +{ + struct ordered_event *new; + + new = alloc_event(oe); + if (new) { + new->timestamp = timestamp; + queue_event(oe, new); + } + + return new; +} + +static void +ordered_events__delete(struct ordered_events *oe, struct ordered_event *event) +{ + list_del(&event->list); + list_add(&event->list, &oe->cache); + oe->nr_events--; +} + static int perf_session_deliver_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, @@ -506,10 +600,8 @@ static int ordered_events__flush(struct perf_session *s, return ret; } + ordered_events__delete(oe, iter); oe->last_flush = iter->timestamp; - list_del(&iter->list); - list_add(&iter->list, &oe->cache); - oe->nr_events--; if (show_progress) ui_progress__update(&prog, 1); @@ -573,59 +665,10 @@ static int process_finished_round(struct perf_tool *tool, return ret; } -/* The queue is ordered by time */ -static void __queue_event(struct ordered_event *new, struct perf_session *s) -{ - struct ordered_events *oe = &s->ordered_events; - struct ordered_event *last = oe->last; - u64 timestamp = new->timestamp; - struct list_head *p; - - ++oe->nr_events; - oe->last = new; - - if (!last) { - list_add(&new->list, &oe->events); - oe->max_timestamp = timestamp; - return; - } - - /* - * last event might point to some random place in the list as it's - * the last queued event. We expect that the new event is close to - * this. - */ - if (last->timestamp <= timestamp) { - while (last->timestamp <= timestamp) { - p = last->list.next; - if (p == &oe->events) { - list_add_tail(&new->list, &oe->events); - oe->max_timestamp = timestamp; - return; - } - last = list_entry(p, struct ordered_event, list); - } - list_add_tail(&new->list, &last->list); - } else { - while (last->timestamp > timestamp) { - p = last->list.prev; - if (p == &oe->events) { - list_add(&new->list, &oe->events); - return; - } - last = list_entry(p, struct ordered_event, list); - } - list_add(&new->list, &last->list); - } -} - -#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) - int perf_session_queue_event(struct perf_session *s, union perf_event *event, struct perf_sample *sample, u64 file_offset) { struct ordered_events *oe = &s->ordered_events; - struct list_head *cache = &oe->cache; u64 timestamp = sample->time; struct ordered_event *new; @@ -637,28 +680,12 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, return -EINVAL; } - if (!list_empty(cache)) { - new = list_entry(cache->next, struct ordered_event, list); - list_del(&new->list); - } else if (oe->buffer) { - new = oe->buffer + oe->buffer_idx; - if (++oe->buffer_idx == MAX_SAMPLE_BUFFER) - oe->buffer = NULL; - } else { - oe->buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new)); - if (!oe->buffer) - return -ENOMEM; - list_add(&oe->buffer->list, &oe->to_free); - oe->buffer_idx = 2; - new = oe->buffer + 1; - } + new = ordered_events__new(oe, timestamp); + if (!new) + return -ENOMEM; - new->timestamp = timestamp; new->file_offset = file_offset; new->event = event; - - __queue_event(new, s); - return 0; } -- GitLab From d8836b5d1736632aa1a38a8ed0c9361c96d7c95a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 5 Jun 2014 10:29:45 +0200 Subject: [PATCH 0168/5088] perf tools: Factor ordered_events__flush to be more generic Centralizing the next_flush calculation under the ordered_events__flush function. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-srwunsy7o5wl17vpt4a10oxp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 47 ++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ff0188c65783..72c7b0d3d0dc 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -451,6 +451,11 @@ struct ordered_event { struct list_head list; }; +enum oe_flush { + OE_FLUSH__FINAL, + OE_FLUSH__ROUND, +}; + static void perf_session_free_sample_buffers(struct perf_session *session) { struct ordered_events *oe = &session->ordered_events; @@ -564,8 +569,8 @@ static int perf_session_deliver_event(struct perf_session *session, struct perf_tool *tool, u64 file_offset); -static int ordered_events__flush(struct perf_session *s, - struct perf_tool *tool) +static int __ordered_events__flush(struct perf_session *s, + struct perf_tool *tool) { struct ordered_events *oe = &s->ordered_events; struct list_head *head = &oe->events; @@ -615,6 +620,32 @@ static int ordered_events__flush(struct perf_session *s, return 0; } +static int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, + enum oe_flush how) +{ + struct ordered_events *oe = &s->ordered_events; + int err; + + switch (how) { + case OE_FLUSH__FINAL: + oe->next_flush = ULLONG_MAX; + break; + + case OE_FLUSH__ROUND: + default: + break; + }; + + err = __ordered_events__flush(s, tool); + + if (!err) { + if (how == OE_FLUSH__ROUND) + oe->next_flush = oe->max_timestamp; + } + + return err; +} + /* * When perf record finishes a pass on every buffers, it records this pseudo * event. @@ -658,11 +689,7 @@ static int process_finished_round(struct perf_tool *tool, union perf_event *event __maybe_unused, struct perf_session *session) { - int ret = ordered_events__flush(session, tool); - if (!ret) - session->ordered_events.next_flush = session->ordered_events.max_timestamp; - - return ret; + return ordered_events__flush(session, tool, OE_FLUSH__ROUND); } int perf_session_queue_event(struct perf_session *s, union perf_event *event, @@ -1247,8 +1274,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session, goto more; done: /* do the final flush for ordered samples */ - session->ordered_events.next_flush = ULLONG_MAX; - err = ordered_events__flush(session, tool); + err = ordered_events__flush(session, tool, OE_FLUSH__FINAL); out_err: free(buf); perf_session__warn_about_errors(session, tool); @@ -1393,8 +1419,7 @@ int __perf_session__process_events(struct perf_session *session, out: /* do the final flush for ordered samples */ - session->ordered_events.next_flush = ULLONG_MAX; - err = ordered_events__flush(session, tool); + err = ordered_events__flush(session, tool, OE_FLUSH__FINAL); out_err: ui_progress__finish(); perf_session__warn_about_errors(session, tool); -- GitLab From 8d99a6ceebe862ac4afd832cdab332ee7b3b5599 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Jun 2014 15:09:35 +0200 Subject: [PATCH 0169/5088] perf tools: Limit ordered events queue size Add limit to the ordered events queue allocation. This way we will be able to control the size of the queue buffers. There's no limit at the moment (it's set to (u64) -1). The config code will come in following patches. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-lw1ny3mk4ctb6su5ght5rsng@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 12 +++++++++--- tools/perf/util/session.h | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 72c7b0d3d0dc..8d4538c91076 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -78,6 +78,8 @@ struct perf_session *perf_session__new(struct perf_data_file *file, INIT_LIST_HEAD(&session->ordered_events.events); INIT_LIST_HEAD(&session->ordered_events.cache); INIT_LIST_HEAD(&session->ordered_events.to_free); + session->ordered_events.max_alloc_size = (u64) -1; + session->ordered_events.cur_alloc_size = 0; machines__init(&session->machines); if (file) { @@ -518,7 +520,7 @@ static void queue_event(struct ordered_events *oe, struct ordered_event *new) static struct ordered_event *alloc_event(struct ordered_events *oe) { struct list_head *cache = &oe->cache; - struct ordered_event *new; + struct ordered_event *new = NULL; if (!list_empty(cache)) { new = list_entry(cache->next, struct ordered_event, list); @@ -527,10 +529,14 @@ static struct ordered_event *alloc_event(struct ordered_events *oe) new = oe->buffer + oe->buffer_idx; if (++oe->buffer_idx == MAX_SAMPLE_BUFFER) oe->buffer = NULL; - } else { - oe->buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new)); + } else if (oe->cur_alloc_size < oe->max_alloc_size) { + size_t size = MAX_SAMPLE_BUFFER * sizeof(*new); + + oe->buffer = malloc(size); if (!oe->buffer) return NULL; + + oe->cur_alloc_size += size; list_add(&oe->buffer->list, &oe->to_free); /* First entry is abused to maintain the to_free list. */ diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 419eb50e1cd3..e2fbaf2567e1 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -20,6 +20,8 @@ struct ordered_events { u64 last_flush; u64 next_flush; u64 max_timestamp; + u64 max_alloc_size; + u64 cur_alloc_size; struct list_head events; struct list_head cache; struct list_head to_free; -- GitLab From d40b4a15ab2bfcfa7d946b69ca1f12c93b22d169 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 1 Aug 2014 13:01:04 -0300 Subject: [PATCH 0170/5088] perf tools: Flush ordered events in case of allocation failure In previous patches we added a limit for ordered events queue allocation size. If we reach this size we need to flush (part of) the queue to get some free buffers. The current functionality is not affected, because the limit is hard coded to (u64) -1. The configuration code for size will come in following patches. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-ggcas0xdq847fi85bz73do2e@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 2 +- tools/perf/util/session.c | 29 +++++++++++++++++++++++++++-- tools/perf/util/session.h | 3 ++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 258a5274099d..7ccceadcd9f8 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -732,7 +732,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, return -1; } - err = perf_session_queue_event(kvm->session, event, &sample, 0); + err = perf_session_queue_event(kvm->session, event, &kvm->tool, &sample, 0); /* * FIXME: Here we can't consume the event, as perf_session_queue_event will * point to it, and it'll get possibly overwritten by the kernel. diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 8d4538c91076..bd2483b6b446 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -14,6 +14,7 @@ #include "util.h" #include "cpumap.h" #include "perf_regs.h" +#include "asm/bug.h" static int perf_session__open(struct perf_session *session) { @@ -456,6 +457,7 @@ struct ordered_event { enum oe_flush { OE_FLUSH__FINAL, OE_FLUSH__ROUND, + OE_FLUSH__HALF, }; static void perf_session_free_sample_buffers(struct perf_session *session) @@ -637,6 +639,23 @@ static int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, oe->next_flush = ULLONG_MAX; break; + case OE_FLUSH__HALF: + { + struct ordered_event *first, *last; + struct list_head *head = &oe->events; + + first = list_entry(head->next, struct ordered_event, list); + last = oe->last; + + /* Warn if we are called before any event got allocated. */ + if (WARN_ONCE(!last || list_empty(head), "empty queue")) + return 0; + + oe->next_flush = first->timestamp; + oe->next_flush += (last->timestamp - first->timestamp) / 2; + break; + } + case OE_FLUSH__ROUND: default: break; @@ -699,7 +718,8 @@ static int process_finished_round(struct perf_tool *tool, } int perf_session_queue_event(struct perf_session *s, union perf_event *event, - struct perf_sample *sample, u64 file_offset) + struct perf_tool *tool, struct perf_sample *sample, + u64 file_offset) { struct ordered_events *oe = &s->ordered_events; u64 timestamp = sample->time; @@ -714,6 +734,11 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, } new = ordered_events__new(oe, timestamp); + if (!new) { + ordered_events__flush(s, tool, OE_FLUSH__HALF); + new = ordered_events__new(oe, timestamp); + } + if (!new) return -ENOMEM; @@ -1121,7 +1146,7 @@ static s64 perf_session__process_event(struct perf_session *session, return ret; if (tool->ordered_events) { - ret = perf_session_queue_event(session, event, &sample, + ret = perf_session_queue_event(session, event, tool, &sample, file_offset); if (ret != -ETIME) return ret; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index e2fbaf2567e1..a09e3c8d825a 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -67,7 +67,8 @@ int perf_session__process_events(struct perf_session *session, struct perf_tool *tool); int perf_session_queue_event(struct perf_session *s, union perf_event *event, - struct perf_sample *sample, u64 file_offset); + struct perf_tool *tool, struct perf_sample *sample, + u64 file_offset); void perf_tool__fill_defaults(struct perf_tool *tool); -- GitLab From 79a30fe4f3758c98e1b7a474952b9701d513e580 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 10 Jun 2014 22:31:35 +0200 Subject: [PATCH 0171/5088] perf tools: Make perf_session__deliver_event global Making perf_session__deliver_event global function, as it will be called from another object in following patch. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-rz7s2b8uwv567bigckh75gvk@git.kernel.org [ Fixup naming to match class__method schema, as now is more widely exposed ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 23 ++++++++--------------- tools/perf/util/session.h | 5 +++++ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index bd2483b6b446..ed6b7f14631f 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -571,12 +571,6 @@ ordered_events__delete(struct ordered_events *oe, struct ordered_event *event) oe->nr_events--; } -static int perf_session_deliver_event(struct perf_session *session, - union perf_event *event, - struct perf_sample *sample, - struct perf_tool *tool, - u64 file_offset); - static int __ordered_events__flush(struct perf_session *s, struct perf_tool *tool) { @@ -607,8 +601,8 @@ static int __ordered_events__flush(struct perf_session *s, if (ret) pr_err("Can't parse sample, err = %d\n", ret); else { - ret = perf_session_deliver_event(s, iter->event, &sample, tool, - iter->file_offset); + ret = perf_session__deliver_event(s, iter->event, &sample, tool, + iter->file_offset); if (ret) return ret; } @@ -1003,11 +997,10 @@ perf_session__deliver_sample(struct perf_session *session, &sample->read.one, machine); } -static int perf_session_deliver_event(struct perf_session *session, - union perf_event *event, - struct perf_sample *sample, - struct perf_tool *tool, - u64 file_offset) +int perf_session__deliver_event(struct perf_session *session, + union perf_event *event, + struct perf_sample *sample, + struct perf_tool *tool, u64 file_offset) { struct perf_evsel *evsel; struct machine *machine; @@ -1152,8 +1145,8 @@ static s64 perf_session__process_event(struct perf_session *session, return ret; } - return perf_session_deliver_event(session, event, &sample, tool, - file_offset); + return perf_session__deliver_event(session, event, &sample, tool, + file_offset); } void perf_event_header__bswap(struct perf_event_header *hdr) diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index a09e3c8d825a..03da1cb14dc1 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -72,6 +72,11 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, void perf_tool__fill_defaults(struct perf_tool *tool); +int perf_session__deliver_event(struct perf_session *session, + union perf_event *event, + struct perf_sample *sample, + struct perf_tool *tool, u64 file_offset); + int perf_session__resolve_callchain(struct perf_session *session, struct perf_evsel *evsel, struct thread *thread, -- GitLab From 5f86b80b85f0dcd05fd1471eac6984181a707c4f Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 1 Aug 2014 13:02:58 -0300 Subject: [PATCH 0172/5088] perf tools: Create ordered-events object Move ordered events code into separated object ordered-events.[ch]. No functional change was intended. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-1ge3rilgudszbl87cejm1tfg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 2 + tools/perf/util/ordered-events.c | 196 +++++++++++++++++++++++++++++ tools/perf/util/ordered-events.h | 41 ++++++ tools/perf/util/session.c | 206 ------------------------------- tools/perf/util/session.h | 17 +-- 5 files changed, 240 insertions(+), 222 deletions(-) create mode 100644 tools/perf/util/ordered-events.c create mode 100644 tools/perf/util/ordered-events.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 2240974b7745..1ea31e275b4d 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -263,6 +263,7 @@ LIB_H += util/xyarray.h LIB_H += util/header.h LIB_H += util/help.h LIB_H += util/session.h +LIB_H += util/ordered-events.h LIB_H += util/strbuf.h LIB_H += util/strlist.h LIB_H += util/strfilter.h @@ -347,6 +348,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o LIB_OBJS += $(OUTPUT)util/map.o LIB_OBJS += $(OUTPUT)util/pstack.o LIB_OBJS += $(OUTPUT)util/session.o +LIB_OBJS += $(OUTPUT)util/ordered-events.o LIB_OBJS += $(OUTPUT)util/comm.o LIB_OBJS += $(OUTPUT)util/thread.o LIB_OBJS += $(OUTPUT)util/thread_map.o diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c new file mode 100644 index 000000000000..95f8211ccdde --- /dev/null +++ b/tools/perf/util/ordered-events.c @@ -0,0 +1,196 @@ +#include +#include "ordered-events.h" +#include "evlist.h" +#include "session.h" +#include "asm/bug.h" +#include "debug.h" + +static void queue_event(struct ordered_events *oe, struct ordered_event *new) +{ + struct ordered_event *last = oe->last; + u64 timestamp = new->timestamp; + struct list_head *p; + + ++oe->nr_events; + oe->last = new; + + if (!last) { + list_add(&new->list, &oe->events); + oe->max_timestamp = timestamp; + return; + } + + /* + * last event might point to some random place in the list as it's + * the last queued event. We expect that the new event is close to + * this. + */ + if (last->timestamp <= timestamp) { + while (last->timestamp <= timestamp) { + p = last->list.next; + if (p == &oe->events) { + list_add_tail(&new->list, &oe->events); + oe->max_timestamp = timestamp; + return; + } + last = list_entry(p, struct ordered_event, list); + } + list_add_tail(&new->list, &last->list); + } else { + while (last->timestamp > timestamp) { + p = last->list.prev; + if (p == &oe->events) { + list_add(&new->list, &oe->events); + return; + } + last = list_entry(p, struct ordered_event, list); + } + list_add(&new->list, &last->list); + } +} + +#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) +static struct ordered_event *alloc_event(struct ordered_events *oe) +{ + struct list_head *cache = &oe->cache; + struct ordered_event *new = NULL; + + if (!list_empty(cache)) { + new = list_entry(cache->next, struct ordered_event, list); + list_del(&new->list); + } else if (oe->buffer) { + new = oe->buffer + oe->buffer_idx; + if (++oe->buffer_idx == MAX_SAMPLE_BUFFER) + oe->buffer = NULL; + } else if (oe->cur_alloc_size < oe->max_alloc_size) { + size_t size = MAX_SAMPLE_BUFFER * sizeof(*new); + + oe->buffer = malloc(size); + if (!oe->buffer) + return NULL; + + oe->cur_alloc_size += size; + list_add(&oe->buffer->list, &oe->to_free); + + /* First entry is abused to maintain the to_free list. */ + oe->buffer_idx = 2; + new = oe->buffer + 1; + } + + return new; +} + +struct ordered_event * +ordered_events__new(struct ordered_events *oe, u64 timestamp) +{ + struct ordered_event *new; + + new = alloc_event(oe); + if (new) { + new->timestamp = timestamp; + queue_event(oe, new); + } + + return new; +} + +void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event) +{ + list_del(&event->list); + list_add(&event->list, &oe->cache); + oe->nr_events--; +} + +static int __ordered_events__flush(struct perf_session *s, + struct perf_tool *tool) +{ + struct ordered_events *oe = &s->ordered_events; + struct list_head *head = &oe->events; + struct ordered_event *tmp, *iter; + struct perf_sample sample; + u64 limit = oe->next_flush; + u64 last_ts = oe->last ? oe->last->timestamp : 0ULL; + bool show_progress = limit == ULLONG_MAX; + struct ui_progress prog; + int ret; + + if (!tool->ordered_events || !limit) + return 0; + + if (show_progress) + ui_progress__init(&prog, oe->nr_events, "Processing time ordered events..."); + + list_for_each_entry_safe(iter, tmp, head, list) { + if (session_done()) + return 0; + + if (iter->timestamp > limit) + break; + + ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample); + if (ret) + pr_err("Can't parse sample, err = %d\n", ret); + else { + ret = perf_session__deliver_event(s, iter->event, &sample, tool, + iter->file_offset); + if (ret) + return ret; + } + + ordered_events__delete(oe, iter); + oe->last_flush = iter->timestamp; + + if (show_progress) + ui_progress__update(&prog, 1); + } + + if (list_empty(head)) + oe->last = NULL; + else if (last_ts <= limit) + oe->last = list_entry(head->prev, struct ordered_event, list); + + return 0; +} + +int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, + enum oe_flush how) +{ + struct ordered_events *oe = &s->ordered_events; + int err; + + switch (how) { + case OE_FLUSH__FINAL: + oe->next_flush = ULLONG_MAX; + break; + + case OE_FLUSH__HALF: + { + struct ordered_event *first, *last; + struct list_head *head = &oe->events; + + first = list_entry(head->next, struct ordered_event, list); + last = oe->last; + + /* Warn if we are called before any event got allocated. */ + if (WARN_ONCE(!last || list_empty(head), "empty queue")) + return 0; + + oe->next_flush = first->timestamp; + oe->next_flush += (last->timestamp - first->timestamp) / 2; + break; + } + + case OE_FLUSH__ROUND: + default: + break; + }; + + err = __ordered_events__flush(s, tool); + + if (!err) { + if (how == OE_FLUSH__ROUND) + oe->next_flush = oe->max_timestamp; + } + + return err; +} diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h new file mode 100644 index 000000000000..8309983bdd70 --- /dev/null +++ b/tools/perf/util/ordered-events.h @@ -0,0 +1,41 @@ +#ifndef __ORDERED_EVENTS_H +#define __ORDERED_EVENTS_H + +#include +#include "tool.h" + +struct perf_session; + +struct ordered_event { + u64 timestamp; + u64 file_offset; + union perf_event *event; + struct list_head list; +}; + +enum oe_flush { + OE_FLUSH__FINAL, + OE_FLUSH__ROUND, + OE_FLUSH__HALF, +}; + +struct ordered_events { + u64 last_flush; + u64 next_flush; + u64 max_timestamp; + u64 max_alloc_size; + u64 cur_alloc_size; + struct list_head events; + struct list_head cache; + struct list_head to_free; + struct ordered_event *buffer; + struct ordered_event *last; + int buffer_idx; + unsigned int nr_events; +}; + +struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp); +void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event); +int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, + enum oe_flush how); +#endif /* __ORDERED_EVENTS_H */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ed6b7f14631f..0ccf051247f6 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -14,7 +14,6 @@ #include "util.h" #include "cpumap.h" #include "perf_regs.h" -#include "asm/bug.h" static int perf_session__open(struct perf_session *session) { @@ -447,19 +446,6 @@ static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_HEADER_MAX] = NULL, }; -struct ordered_event { - u64 timestamp; - u64 file_offset; - union perf_event *event; - struct list_head list; -}; - -enum oe_flush { - OE_FLUSH__FINAL, - OE_FLUSH__ROUND, - OE_FLUSH__HALF, -}; - static void perf_session_free_sample_buffers(struct perf_session *session) { struct ordered_events *oe = &session->ordered_events; @@ -473,198 +459,6 @@ static void perf_session_free_sample_buffers(struct perf_session *session) } } -/* The queue is ordered by time */ -static void queue_event(struct ordered_events *oe, struct ordered_event *new) -{ - struct ordered_event *last = oe->last; - u64 timestamp = new->timestamp; - struct list_head *p; - - ++oe->nr_events; - oe->last = new; - - if (!last) { - list_add(&new->list, &oe->events); - oe->max_timestamp = timestamp; - return; - } - - /* - * last event might point to some random place in the list as it's - * the last queued event. We expect that the new event is close to - * this. - */ - if (last->timestamp <= timestamp) { - while (last->timestamp <= timestamp) { - p = last->list.next; - if (p == &oe->events) { - list_add_tail(&new->list, &oe->events); - oe->max_timestamp = timestamp; - return; - } - last = list_entry(p, struct ordered_event, list); - } - list_add_tail(&new->list, &last->list); - } else { - while (last->timestamp > timestamp) { - p = last->list.prev; - if (p == &oe->events) { - list_add(&new->list, &oe->events); - return; - } - last = list_entry(p, struct ordered_event, list); - } - list_add(&new->list, &last->list); - } -} - -#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) -static struct ordered_event *alloc_event(struct ordered_events *oe) -{ - struct list_head *cache = &oe->cache; - struct ordered_event *new = NULL; - - if (!list_empty(cache)) { - new = list_entry(cache->next, struct ordered_event, list); - list_del(&new->list); - } else if (oe->buffer) { - new = oe->buffer + oe->buffer_idx; - if (++oe->buffer_idx == MAX_SAMPLE_BUFFER) - oe->buffer = NULL; - } else if (oe->cur_alloc_size < oe->max_alloc_size) { - size_t size = MAX_SAMPLE_BUFFER * sizeof(*new); - - oe->buffer = malloc(size); - if (!oe->buffer) - return NULL; - - oe->cur_alloc_size += size; - list_add(&oe->buffer->list, &oe->to_free); - - /* First entry is abused to maintain the to_free list. */ - oe->buffer_idx = 2; - new = oe->buffer + 1; - } - - return new; -} - -static struct ordered_event * -ordered_events__new(struct ordered_events *oe, u64 timestamp) -{ - struct ordered_event *new; - - new = alloc_event(oe); - if (new) { - new->timestamp = timestamp; - queue_event(oe, new); - } - - return new; -} - -static void -ordered_events__delete(struct ordered_events *oe, struct ordered_event *event) -{ - list_del(&event->list); - list_add(&event->list, &oe->cache); - oe->nr_events--; -} - -static int __ordered_events__flush(struct perf_session *s, - struct perf_tool *tool) -{ - struct ordered_events *oe = &s->ordered_events; - struct list_head *head = &oe->events; - struct ordered_event *tmp, *iter; - struct perf_sample sample; - u64 limit = oe->next_flush; - u64 last_ts = oe->last ? oe->last->timestamp : 0ULL; - bool show_progress = limit == ULLONG_MAX; - struct ui_progress prog; - int ret; - - if (!tool->ordered_events || !limit) - return 0; - - if (show_progress) - ui_progress__init(&prog, oe->nr_events, "Processing time ordered events..."); - - list_for_each_entry_safe(iter, tmp, head, list) { - if (session_done()) - return 0; - - if (iter->timestamp > limit) - break; - - ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample); - if (ret) - pr_err("Can't parse sample, err = %d\n", ret); - else { - ret = perf_session__deliver_event(s, iter->event, &sample, tool, - iter->file_offset); - if (ret) - return ret; - } - - ordered_events__delete(oe, iter); - oe->last_flush = iter->timestamp; - - if (show_progress) - ui_progress__update(&prog, 1); - } - - if (list_empty(head)) - oe->last = NULL; - else if (last_ts <= limit) - oe->last = list_entry(head->prev, struct ordered_event, list); - - return 0; -} - -static int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, - enum oe_flush how) -{ - struct ordered_events *oe = &s->ordered_events; - int err; - - switch (how) { - case OE_FLUSH__FINAL: - oe->next_flush = ULLONG_MAX; - break; - - case OE_FLUSH__HALF: - { - struct ordered_event *first, *last; - struct list_head *head = &oe->events; - - first = list_entry(head->next, struct ordered_event, list); - last = oe->last; - - /* Warn if we are called before any event got allocated. */ - if (WARN_ONCE(!last || list_empty(head), "empty queue")) - return 0; - - oe->next_flush = first->timestamp; - oe->next_flush += (last->timestamp - first->timestamp) / 2; - break; - } - - case OE_FLUSH__ROUND: - default: - break; - }; - - err = __ordered_events__flush(s, tool); - - if (!err) { - if (how == OE_FLUSH__ROUND) - oe->next_flush = oe->max_timestamp; - } - - return err; -} - /* * When perf record finishes a pass on every buffers, it records this pseudo * event. diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 03da1cb14dc1..0630e658f8be 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -9,28 +9,13 @@ #include "symbol.h" #include "thread.h" #include "data.h" +#include "ordered-events.h" #include #include -struct ordered_event; struct ip_callchain; struct thread; -struct ordered_events { - u64 last_flush; - u64 next_flush; - u64 max_timestamp; - u64 max_alloc_size; - u64 cur_alloc_size; - struct list_head events; - struct list_head cache; - struct list_head to_free; - struct ordered_event *buffer; - struct ordered_event *last; - int buffer_idx; - unsigned int nr_events; -}; - struct perf_session { struct perf_header header; struct machines machines; -- GitLab From fa4e5c67a2d169b9ef83f51b94e1d4a562ddfc0f Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 15 Jun 2014 19:46:08 +0200 Subject: [PATCH 0173/5088] perf tools: Use list_move in ordered_events_delete function As Namhyung pointed out we can use list_move in ordered_events_delete. Signed-off-by: Jiri Olsa Suggested-by: Namhyung Kim Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-m8ae5s5cuwyytitgb6iqilid@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ordered-events.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index 95f8211ccdde..be6a48ce3eea 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -96,8 +96,7 @@ ordered_events__new(struct ordered_events *oe, u64 timestamp) void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event) { - list_del(&event->list); - list_add(&event->list, &oe->cache); + list_move(&event->list, &oe->cache); oe->nr_events--; } -- GitLab From 36522f5cf2ad280c971557e04120d52f9330ed36 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 10 Jun 2014 22:47:40 +0200 Subject: [PATCH 0174/5088] perf tools: Add ordered_events__init function Adding ordered_events__init function for struct ordered_events struct initialization. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-g6dx35hed8g14eh1ygx4uzp6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ordered-events.c | 9 +++++++++ tools/perf/util/ordered-events.h | 1 + tools/perf/util/session.c | 6 +----- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index be6a48ce3eea..7b8923e12dc7 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -193,3 +193,12 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, return err; } + +void ordered_events__init(struct ordered_events *oe) +{ + INIT_LIST_HEAD(&oe->events); + INIT_LIST_HEAD(&oe->cache); + INIT_LIST_HEAD(&oe->to_free); + oe->max_alloc_size = (u64) -1; + oe->cur_alloc_size = 0; +} diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h index 8309983bdd70..62f9945319b6 100644 --- a/tools/perf/util/ordered-events.h +++ b/tools/perf/util/ordered-events.h @@ -38,4 +38,5 @@ struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timesta void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event); int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, enum oe_flush how); +void ordered_events__init(struct ordered_events *oe); #endif /* __ORDERED_EVENTS_H */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0ccf051247f6..7f5851e433bb 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -75,11 +75,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file, goto out; session->repipe = repipe; - INIT_LIST_HEAD(&session->ordered_events.events); - INIT_LIST_HEAD(&session->ordered_events.cache); - INIT_LIST_HEAD(&session->ordered_events.to_free); - session->ordered_events.max_alloc_size = (u64) -1; - session->ordered_events.cur_alloc_size = 0; + ordered_events__init(&session->ordered_events); machines__init(&session->machines); if (file) { -- GitLab From adc56ed1e01f1c43fc7bf75340f11f4ad5e11145 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 10 Jun 2014 22:50:03 +0200 Subject: [PATCH 0175/5088] perf tools: Add ordered_events__free function Adding ordered_events__free function to release all the struct ordered_events data. It's replacement for former perf_session_free_sample_buffers function. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-urraa8ccay4o14wambjraws7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ordered-events.c | 11 +++++++++++ tools/perf/util/ordered-events.h | 1 + tools/perf/util/session.c | 17 ++--------------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index 7b8923e12dc7..381d5fea1131 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -202,3 +202,14 @@ void ordered_events__init(struct ordered_events *oe) oe->max_alloc_size = (u64) -1; oe->cur_alloc_size = 0; } + +void ordered_events__free(struct ordered_events *oe) +{ + while (!list_empty(&oe->to_free)) { + struct ordered_event *event; + + event = list_entry(oe->to_free.next, struct ordered_event, list); + list_del(&event->list); + free(event); + } +} diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h index 62f9945319b6..6036bd657073 100644 --- a/tools/perf/util/ordered-events.h +++ b/tools/perf/util/ordered-events.h @@ -39,4 +39,5 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, enum oe_flush how); void ordered_events__init(struct ordered_events *oe); +void ordered_events__free(struct ordered_events *oe); #endif /* __ORDERED_EVENTS_H */ diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 7f5851e433bb..7d8dbf213d64 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -442,19 +442,6 @@ static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_HEADER_MAX] = NULL, }; -static void perf_session_free_sample_buffers(struct perf_session *session) -{ - struct ordered_events *oe = &session->ordered_events; - - while (!list_empty(&oe->to_free)) { - struct ordered_event *event; - - event = list_entry(oe->to_free.next, struct ordered_event, list); - list_del(&event->list); - free(event); - } -} - /* * When perf record finishes a pass on every buffers, it records this pseudo * event. @@ -1092,7 +1079,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session, out_err: free(buf); perf_session__warn_about_errors(session, tool); - perf_session_free_sample_buffers(session); + ordered_events__free(&session->ordered_events); return err; } @@ -1237,7 +1224,7 @@ int __perf_session__process_events(struct perf_session *session, out_err: ui_progress__finish(); perf_session__warn_about_errors(session, tool); - perf_session_free_sample_buffers(session); + ordered_events__free(&session->ordered_events); session->one_mmap = false; return err; } -- GitLab From 94c0655fc16b0c09edc21cadddbeef95c408f3e7 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 6 Jun 2014 05:27:28 -0400 Subject: [PATCH 0176/5088] perf tools: Add perf_config_u64 function Adding perf_config_u64 function to be able to parse 'llong' values out of config file. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-ni6gqdlvw7khp74r9htvklkb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cache.h | 1 + tools/perf/util/config.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 7b176dd02e1a..5cf9e1b5989d 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -22,6 +22,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *); extern int perf_default_config(const char *, const char *, void *); extern int perf_config(config_fn_t fn, void *); extern int perf_config_int(const char *, const char *); +extern u64 perf_config_u64(const char *, const char *); extern int perf_config_bool(const char *, const char *); extern int config_error_nonbool(const char *); extern const char *perf_config_dirname(const char *, const char *); diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 1e5e2e5af6b1..9970b8b0190b 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -286,6 +286,21 @@ static int parse_unit_factor(const char *end, unsigned long *val) return 0; } +static int perf_parse_llong(const char *value, long long *ret) +{ + if (value && *value) { + char *end; + long long val = strtoll(value, &end, 0); + unsigned long factor = 1; + + if (!parse_unit_factor(end, &factor)) + return 0; + *ret = val * factor; + return 1; + } + return 0; +} + static int perf_parse_long(const char *value, long *ret) { if (value && *value) { @@ -307,6 +322,15 @@ static void die_bad_config(const char *name) die("bad config value for '%s'", name); } +u64 perf_config_u64(const char *name, const char *value) +{ + long long ret = 0; + + if (!perf_parse_llong(value, &ret)) + die_bad_config(name); + return (u64) ret; +} + int perf_config_int(const char *name, const char *value) { long ret = 0; -- GitLab From 94786b67b5f4577c16486e8eb10ff045e59f80ef Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 5 Jun 2014 11:00:20 +0200 Subject: [PATCH 0177/5088] perf tools: Add report.queue-size config file option Adding report.queue-size config file option to setup the maximum allocation size for session's struct ordered_events object. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-lm42mbpu0cwljpyy8vw5y26n@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 13 ++++++++++++- tools/perf/util/ordered-events.h | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index c72cc5a12144..041e93da13e4 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -58,17 +58,19 @@ struct report { const char *symbol_filter_str; float min_percent; u64 nr_entries; + u64 queue_size; DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); }; static int report__config(const char *var, const char *value, void *cb) { + struct report *rep = cb; + if (!strcmp(var, "report.group")) { symbol_conf.event_group = perf_config_bool(var, value); return 0; } if (!strcmp(var, "report.percent-limit")) { - struct report *rep = cb; rep->min_percent = strtof(value, NULL); return 0; } @@ -76,6 +78,10 @@ static int report__config(const char *var, const char *value, void *cb) symbol_conf.cumulate_callchain = perf_config_bool(var, value); return 0; } + if (!strcmp(var, "report.queue-size")) { + rep->queue_size = perf_config_u64(var, value); + return 0; + } return perf_default_config(var, value, cb); } @@ -714,6 +720,11 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) if (session == NULL) return -ENOMEM; + if (report.queue_size) { + ordered_events__set_alloc_size(&session->ordered_events, + report.queue_size); + } + report.session = session; has_br_stack = perf_header__has_feat(&session->header, diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h index 6036bd657073..2ce847fb48a5 100644 --- a/tools/perf/util/ordered-events.h +++ b/tools/perf/util/ordered-events.h @@ -40,4 +40,10 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, enum oe_flush how); void ordered_events__init(struct ordered_events *oe); void ordered_events__free(struct ordered_events *oe); + +static inline +void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size) +{ + oe->max_alloc_size = size; +} #endif /* __ORDERED_EVENTS_H */ -- GitLab From cee3ab9caa7ae5ee81027e60c0109063664d9217 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 11 Jul 2014 14:49:54 +0200 Subject: [PATCH 0178/5088] perf tools: Add debug prints for ordered events queue Adding some prints for ordered events queue, to help debug issues. Adding debug_ordered_events debug variable to be able to enable ordered events debug messages using: $ perf --debug ordered-events=2 report ... Also using oe pointer in perf_session__queue_event instead of chained session variable dereferencing. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-7p3mnnopjvsp9nmk9msqcfkm@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/debug.c | 36 +++++++++++++++++++++++++++++++- tools/perf/util/debug.h | 8 +++++++ tools/perf/util/ordered-events.c | 26 +++++++++++++++++++++++ tools/perf/util/session.c | 4 +++- 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 71d419362634..ba357f3226c6 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -13,8 +13,12 @@ #include "util.h" #include "target.h" +#define NSECS_PER_SEC 1000000000ULL +#define NSECS_PER_USEC 1000ULL + int verbose; bool dump_trace = false, quiet = false; +int debug_ordered_events; static int _eprintf(int level, int var, const char *fmt, va_list args) { @@ -42,6 +46,35 @@ int eprintf(int level, int var, const char *fmt, ...) return ret; } +static int __eprintf_time(u64 t, const char *fmt, va_list args) +{ + int ret = 0; + u64 secs, usecs, nsecs = t; + + secs = nsecs / NSECS_PER_SEC; + nsecs -= secs * NSECS_PER_SEC; + usecs = nsecs / NSECS_PER_USEC; + + ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ", + secs, usecs); + ret += vfprintf(stderr, fmt, args); + return ret; +} + +int eprintf_time(int level, int var, u64 t, const char *fmt, ...) +{ + int ret = 0; + va_list args; + + if (var >= level) { + va_start(args, fmt); + ret = __eprintf_time(t, fmt, args); + va_end(args); + } + + return ret; +} + /* * Overloading libtraceevent standard info print * function, display with -v in perf. @@ -110,7 +143,8 @@ static struct debug_variable { const char *name; int *ptr; } debug_variables[] = { - { .name = "verbose", .ptr = &verbose }, + { .name = "verbose", .ptr = &verbose }, + { .name = "ordered-events", .ptr = &debug_ordered_events}, { .name = NULL, } }; diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 89fb6b0f7ab2..6944ea3a119b 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -10,6 +10,7 @@ extern int verbose; extern bool quiet, dump_trace; +extern int debug_ordered_events; #ifndef pr_fmt #define pr_fmt(fmt) fmt @@ -29,6 +30,12 @@ extern bool quiet, dump_trace; #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_time_N(n, var, t, fmt, ...) \ + eprintf_time(n, var, t, fmt, ##__VA_ARGS__) + +#define pr_oe_time(t, fmt, ...) pr_time_N(1, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_oe_time2(t, fmt, ...) pr_time_N(2, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__) + int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void trace_event(union perf_event *event); @@ -38,6 +45,7 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); void pr_stat(const char *fmt, ...); int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); +int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__((format(printf, 4, 5))); int perf_debug_option(const char *str); diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index 381d5fea1131..8a8aeab8e7ec 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -1,10 +1,16 @@ #include +#include #include "ordered-events.h" #include "evlist.h" #include "session.h" #include "asm/bug.h" #include "debug.h" +#define pr_N(n, fmt, ...) \ + eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__) + +#define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__) + static void queue_event(struct ordered_events *oe, struct ordered_event *new) { struct ordered_event *last = oe->last; @@ -14,6 +20,8 @@ static void queue_event(struct ordered_events *oe, struct ordered_event *new) ++oe->nr_events; oe->last = new; + pr_oe_time2(timestamp, "queue_event nr_events %u\n", oe->nr_events); + if (!last) { list_add(&new->list, &oe->events); oe->max_timestamp = timestamp; @@ -69,12 +77,17 @@ static struct ordered_event *alloc_event(struct ordered_events *oe) if (!oe->buffer) return NULL; + pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n", + oe->cur_alloc_size, size, oe->max_alloc_size); + oe->cur_alloc_size += size; list_add(&oe->buffer->list, &oe->to_free); /* First entry is abused to maintain the to_free list. */ oe->buffer_idx = 2; new = oe->buffer + 1; + } else { + pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size); } return new; @@ -155,6 +168,11 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, enum oe_flush how) { struct ordered_events *oe = &s->ordered_events; + static const char * const str[] = { + "FINAL", + "ROUND", + "HALF ", + }; int err; switch (how) { @@ -184,6 +202,10 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, break; }; + pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush PRE %s, nr_events %u\n", + str[how], oe->nr_events); + pr_oe_time(oe->max_timestamp, "max_timestamp\n"); + err = __ordered_events__flush(s, tool); if (!err) { @@ -191,6 +213,10 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, oe->next_flush = oe->max_timestamp; } + pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n", + str[how], oe->nr_events); + pr_oe_time(oe->last_flush, "last_flush\n"); + return err; } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 7d8dbf213d64..462be2749462 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -499,8 +499,10 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, if (!timestamp || timestamp == ~0ULL) return -ETIME; - if (timestamp < s->ordered_events.last_flush) { + if (timestamp < oe->last_flush) { printf("Warning: Timestamp below last timeslice flush\n"); + pr_oe_time(timestamp, "out of order event"); + pr_oe_time(oe->last_flush, "last flush"); return -EINVAL; } -- GitLab From b0a45203a75a800015828ac89f2945981019b65b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 12 Jun 2014 09:50:11 +0200 Subject: [PATCH 0179/5088] perf tools: Allow out of order messages in forced flush In forced flush (OE_FLUSH__HALF) we break the rules of the flush timestamp via PERF_RECORD_FINISHED_ROUND event, so we could get out of order event. Do not force error in this case plus changing the output warning to use WARN_ONCE. Signed-off-by: Jiri Olsa Acked-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-8q8794a8nlmpd1u8xrqmcyd2@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ordered-events.c | 4 ++++ tools/perf/util/ordered-events.h | 2 ++ tools/perf/util/session.c | 12 +++++++++--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index 8a8aeab8e7ec..706ce1a66169 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -169,6 +169,7 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, { struct ordered_events *oe = &s->ordered_events; static const char * const str[] = { + "NONE", "FINAL", "ROUND", "HALF ", @@ -198,6 +199,7 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, } case OE_FLUSH__ROUND: + case OE_FLUSH__NONE: default: break; }; @@ -211,6 +213,8 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, if (!err) { if (how == OE_FLUSH__ROUND) oe->next_flush = oe->max_timestamp; + + oe->last_flush_type = how; } pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n", diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h index 2ce847fb48a5..3b2f20542a01 100644 --- a/tools/perf/util/ordered-events.h +++ b/tools/perf/util/ordered-events.h @@ -14,6 +14,7 @@ struct ordered_event { }; enum oe_flush { + OE_FLUSH__NONE, OE_FLUSH__FINAL, OE_FLUSH__ROUND, OE_FLUSH__HALF, @@ -32,6 +33,7 @@ struct ordered_events { struct ordered_event *last; int buffer_idx; unsigned int nr_events; + enum oe_flush last_flush_type; }; struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 462be2749462..7e27f1eb260c 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -14,6 +14,7 @@ #include "util.h" #include "cpumap.h" #include "perf_regs.h" +#include "asm/bug.h" static int perf_session__open(struct perf_session *session) { @@ -500,10 +501,15 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, return -ETIME; if (timestamp < oe->last_flush) { - printf("Warning: Timestamp below last timeslice flush\n"); + WARN_ONCE(1, "Timestamp below last timeslice flush\n"); + pr_oe_time(timestamp, "out of order event"); - pr_oe_time(oe->last_flush, "last flush"); - return -EINVAL; + pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n", + oe->last_flush_type); + + /* We could get out of order messages after forced flush. */ + if (oe->last_flush_type != OE_FLUSH__HALF) + return -EINVAL; } new = ordered_events__new(oe, timestamp); -- GitLab From 63914aca8f7e7a75d0ee027af7b1755c69cc1e2c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 1 Aug 2014 17:46:54 +0200 Subject: [PATCH 0180/5088] perf tools: Show better error message in case we fail to open counters due to EBUSY error Showing better error message in case we fail to open counters due to the EBUSY error. If we detect oprofile daemon process running, we now display following message for EBUSY error: $ perf record ls Error: The PMU counters are busy/taken by another profiler. We found oprofile daemon running, please stop it and try again. In case oprofiled was not detected the current error message stays: $ perf record ls Error: The sys_perf_event_open() syscall returned with 16 (Device or resource busy) for event (cycles). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured? Also changing PERF_FLAG_FD_CLOEXEC detection code not to display error in case of EBUSY error, as it currently does: $ perf record ls Error: perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error 16 (Device or resource busy) perf_event_open(..., 0) failed unexpectedly with error 16 (Device or resource busy) The PMU counters are busy/taken by another profiler. We found oprofile daemon running, please stop it and try again. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: William Cohen Cc: Yann Droneaud Link: http://lkml.kernel.org/r/1406908014-8312-1-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cloexec.c | 4 ++-- tools/perf/util/evsel.c | 6 ++++++ tools/perf/util/util.c | 36 ++++++++++++++++++++++++++++++++++++ tools/perf/util/util.h | 1 + 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index c5d05ec17220..dede0c388ed4 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c @@ -25,7 +25,7 @@ static int perf_flag_probe(void) return 1; } - WARN_ONCE(err != EINVAL, + WARN_ONCE(err != EINVAL && err != EBUSY, "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", err, strerror(err)); @@ -33,7 +33,7 @@ static int perf_flag_probe(void) fd = sys_perf_event_open(&attr, 0, -1, -1, 0); err = errno; - if (WARN_ONCE(fd < 0, + if (WARN_ONCE(fd < 0 && err != EBUSY, "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", err, strerror(err))) return -1; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 92e5235f5377..0c8919decac8 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2039,6 +2039,12 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it."); #endif break; + case EBUSY: + if (find_process("oprofiled")) + return scnprintf(msg, size, + "The PMU counters are busy/taken by another profiler.\n" + "We found oprofile daemon running, please stop it and try again."); + break; default: break; } diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index e52e7461911b..b82a93cb1694 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -536,3 +536,39 @@ void mem_bswap_64(void *src, int byte_size) ++m; } } + +bool find_process(const char *name) +{ + size_t len = strlen(name); + DIR *dir; + struct dirent *d; + int ret = -1; + + dir = opendir(procfs__mountpoint()); + if (!dir) + return -1; + + /* Walk through the directory. */ + while (ret && (d = readdir(dir)) != NULL) { + char path[PATH_MAX]; + char *data; + size_t size; + + if ((d->d_type != DT_DIR) || + !strcmp(".", d->d_name) || + !strcmp("..", d->d_name)) + continue; + + scnprintf(path, sizeof(path), "%s/%s/comm", + procfs__mountpoint(), d->d_name); + + if (filename__read_str(path, &data, &size)) + continue; + + ret = strncmp(name, data, len); + free(data); + } + + closedir(dir); + return ret ? false : true; +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 38af77550c75..03a1ea2266b8 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -346,4 +346,5 @@ void mem_bswap_64(void *src, int byte_size); void mem_bswap_32(void *src, int byte_size); const char *get_filename_for_perf_kvm(void); +bool find_process(const char *name); #endif /* GIT_COMPAT_UTIL_H */ -- GitLab From 64c40908938953d7afa90e9363327875286349e5 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 1 Aug 2014 14:59:31 +0900 Subject: [PATCH 0181/5088] perf kmem: Do not ignore mmap events The perf kmem command didn't process mmap events for some unknown reason and it instead gets symbol info from a running kernel. This is problematic if perf kmem record was run on a different kernel. This patch adds the mmap event handlers and reverts the commit e727ca73f85d ("perf kmem: Resolve kernel symbols again"). Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1406872771-23933-1-git-send-email-namhyung@kernel.org [ Fixed up merge conflict with Jiri's ordered_events rename patch set ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kmem.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index b5721116713b..84b82397a28e 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -256,6 +256,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, static struct perf_tool perf_kmem = { .sample = process_sample_event, .comm = perf_event__process_comm, + .mmap = perf_event__process_mmap, + .mmap2 = perf_event__process_mmap2, .ordered_events = true, }; @@ -424,9 +426,6 @@ static int __cmd_kmem(void) if (session == NULL) return -ENOMEM; - if (perf_session__create_kernel_maps(session) < 0) - goto out_delete; - if (!perf_session__has_traces(session, "kmem record")) goto out_delete; -- GitLab From 56c7d79e49776084b852e451bda5f59dc3bcf894 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 29 Jul 2014 15:57:19 +0900 Subject: [PATCH 0182/5088] perf tools: Fix make PYTHON override Thomas reported that make PYTHON=python2 is not work on some systems. I can reproduce it on my ArchLinux box too. This is because it's overridden by config/feature-checks/Makefile regardless of PYTHON setting. I guess it's a bug slipped into during the feature checking change. Actually, we don't need to check python-config in the feature-checks. We can just pass appropriate FEATURE_CHECK_*FLAGS. Reported-by: Thomas Ilsche Signed-off-by: Namhyung Kim Tested-by: Thomas Ilsche Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Ilsche Link: http://lkml.kernel.org/r/1406617040-26909-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/config/Makefile | 34 +++++++++++++++-------- tools/perf/config/feature-checks/Makefile | 18 ++---------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1f67aa02d240..e05d8f99424d 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -120,6 +120,23 @@ ifdef PARSER_DEBUG CFLAGS += -DPARSER_DEBUG endif +ifndef NO_LIBPYTHON + override PYTHON := \ + $(call get-executable-or-default,PYTHON,python) + override PYTHON_CONFIG := \ + $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config) + + PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) + + PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) + PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) + + FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS) + FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS) + FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS) + FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS) +endif + CFLAGS += -fno-omit-frame-pointer CFLAGS += -ggdb3 CFLAGS += -funwind-tables @@ -482,21 +499,14 @@ define disable-python_code NO_LIBPYTHON := 1 endef -override PYTHON := \ - $(call get-executable-or-default,PYTHON,python) - -ifndef PYTHON - $(call disable-python,python interpreter) +ifdef NO_LIBPYTHON + $(call disable-python) else - PYTHON_WORD := $(call shell-wordify,$(PYTHON)) - - ifdef NO_LIBPYTHON - $(call disable-python) + ifndef PYTHON + $(call disable-python,python interpreter) else - - override PYTHON_CONFIG := \ - $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config) + PYTHON_WORD := $(call shell-wordify,$(PYTHON)) ifndef PYTHON_CONFIG $(call disable-python,python-config tool) diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 6088f8d8a434..72ab2984718e 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile @@ -101,25 +101,11 @@ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) test-libperl.bin: $(BUILD) $(FLAGS_PERL_EMBED) -override PYTHON := python -override PYTHON_CONFIG := python-config - -escape-for-shell-sq = $(subst ','\'',$(1)) -shell-sq = '$(escape-for-shell-sq)' - -PYTHON_CONFIG_SQ = $(call shell-sq,$(PYTHON_CONFIG)) - -PYTHON_EMBED_LDOPTS = $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) -PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) -PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) -FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) - test-libpython.bin: - $(BUILD) $(FLAGS_PYTHON_EMBED) + $(BUILD) test-libpython-version.bin: - $(BUILD) $(FLAGS_PYTHON_EMBED) + $(BUILD) test-libbfd.bin: $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl -- GitLab From 8246de88e95ddef7508f5601d7af85c3ab9e476b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 31 Jul 2014 14:47:35 +0900 Subject: [PATCH 0183/5088] perf tools: Left-align output contents Now perf left-aligns column headers but the contents does not. It should have same alignment. This requires a change in pid sort key - it consists of two part (pid and comm). As length of comm can be vary it'd be better to change the order of them. Thanks to Jiri Olsa for pointing this out. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1406785662-5534-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 14e5a039bc45..eda9ee836cee 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -70,12 +70,12 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { const char *comm = thread__comm_str(he->thread); - return repsep_snprintf(bf, size, "%*s:%5d", width - 6, - comm ?: "", he->thread->tid); + return repsep_snprintf(bf, size, "%5d:%-*s", he->thread->tid, + width - 6, comm ?: ""); } struct sort_entry sort_thread = { - .se_header = "Command: Pid", + .se_header = " Pid:Command", .se_cmp = sort__thread_cmp, .se_snprintf = hist_entry__thread_snprintf, .se_width_idx = HISTC_THREAD, @@ -106,7 +106,7 @@ sort__comm_sort(struct hist_entry *left, struct hist_entry *right) static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm)); + return repsep_snprintf(bf, size, "%-*s", width, comm__str(he->comm)); } struct sort_entry sort_comm = { @@ -305,7 +305,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width __maybe_unused) { - return repsep_snprintf(bf, size, "%s", he->srcline); + return repsep_snprintf(bf, size, "%-s", he->srcline); } struct sort_entry sort_srcline = { -- GitLab From d675107ce6fa988102851e0b0ef06e46c8aa7ac6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 31 Jul 2014 14:47:36 +0900 Subject: [PATCH 0184/5088] perf tools: Make __hpp__fmt() receive an additional len argument So that it can properly handle alignment requirements later. To do that, add percent_color_len_snprintf() fucntion to help coloring of overhead columns. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1406785662-5534-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 14 ++++++----- tools/perf/ui/gtk/hists.c | 8 ++++--- tools/perf/ui/hist.c | 43 +++++++++++++++++----------------- tools/perf/util/color.c | 16 +++++++++++++ tools/perf/util/color.h | 1 + tools/perf/util/hist.h | 4 ++-- 6 files changed, 54 insertions(+), 32 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a94b11fc5e00..02507ba944e3 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -653,17 +653,18 @@ struct hpp_arg { static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) { struct hpp_arg *arg = hpp->ptr; - int ret; + int ret, len; va_list args; double percent; va_start(args, fmt); + len = va_arg(args, int); percent = va_arg(args, double); va_end(args); ui_browser__set_percent_color(arg->b, percent, arg->current_entry); - ret = scnprintf(hpp->buf, hpp->size, fmt, percent); + ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); slsmg_printf("%s", hpp->buf); advance_hpp(hpp, ret); @@ -681,7 +682,7 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ - return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \ + return __hpp__fmt(hpp, he, __hpp_get_##_field, " %*.2f%%", 6, \ __hpp__slsmg_color_printf, true); \ } @@ -697,13 +698,14 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ struct hist_entry *he) \ { \ if (!symbol_conf.cumulate_callchain) { \ - int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \ + int ret = scnprintf(hpp->buf, hpp->size, \ + "%*s", 8, "N/A"); \ slsmg_printf("%s", hpp->buf); \ \ return ret; \ } \ - return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \ - __hpp__slsmg_color_printf, true); \ + return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %*.2f%%", \ + 6, __hpp__slsmg_color_printf, true); \ } __HPP_COLOR_PERCENT_FN(overhead, period) diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 6ca60e482cdc..91f6cd7d2312 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -11,6 +11,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...) { int ret = 0; + int len; va_list args; double percent; const char *markup; @@ -18,6 +19,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...) size_t size = hpp->size; va_start(args, fmt); + len = va_arg(args, int); percent = va_arg(args, double); va_end(args); @@ -25,7 +27,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...) if (markup) ret += scnprintf(buf, size, markup); - ret += scnprintf(buf + ret, size - ret, fmt, percent); + ret += scnprintf(buf + ret, size - ret, fmt, len, percent); if (markup) ret += scnprintf(buf + ret, size - ret, ""); @@ -43,7 +45,7 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ - return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ + return __hpp__fmt(hpp, he, he_get_##_field, " %*.2f%%", 6, \ __percent_color_snprintf, true); \ } @@ -57,7 +59,7 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ - return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \ + return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %*.2f%%", 6, \ __percent_color_snprintf, true); \ } diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 498adb23c02e..c6cffbd0b0e1 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -16,7 +16,7 @@ }) int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, - hpp_field_fn get_field, const char *fmt, + hpp_field_fn get_field, const char *fmt, int len, hpp_snprint_fn print_fn, bool fmt_percent) { int ret; @@ -32,9 +32,9 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, if (total) percent = 100.0 * get_field(he) / total; - ret = hpp__call_print_fn(hpp, print_fn, fmt, percent); + ret = hpp__call_print_fn(hpp, print_fn, fmt, len, percent); } else - ret = hpp__call_print_fn(hpp, print_fn, fmt, get_field(he)); + ret = hpp__call_print_fn(hpp, print_fn, fmt, len, get_field(he)); if (perf_evsel__is_group_event(evsel)) { int prev_idx, idx_delta; @@ -60,19 +60,19 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, */ if (fmt_percent) { ret += hpp__call_print_fn(hpp, print_fn, - fmt, 0.0); + fmt, len, 0.0); } else { ret += hpp__call_print_fn(hpp, print_fn, - fmt, 0ULL); + fmt, len, 0ULL); } } if (fmt_percent) { - ret += hpp__call_print_fn(hpp, print_fn, fmt, + ret += hpp__call_print_fn(hpp, print_fn, fmt, len, 100.0 * period / total); } else { ret += hpp__call_print_fn(hpp, print_fn, fmt, - period); + len, period); } prev_idx = perf_evsel__group_idx(evsel); @@ -86,10 +86,10 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, */ if (fmt_percent) { ret += hpp__call_print_fn(hpp, print_fn, - fmt, 0.0); + fmt, len, 0.0); } else { ret += hpp__call_print_fn(hpp, print_fn, - fmt, 0ULL); + fmt, len, 0ULL); } } } @@ -105,7 +105,7 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, } int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, - hpp_field_fn get_field, const char *fmt, + hpp_field_fn get_field, const char *fmt, int len, hpp_snprint_fn print_fn, bool fmt_percent) { if (!symbol_conf.cumulate_callchain) { @@ -113,7 +113,7 @@ int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, fmt_percent ? 8 : 12, "N/A"); } - return __hpp__fmt(hpp, he, get_field, fmt, print_fn, fmt_percent); + return __hpp__fmt(hpp, he, get_field, fmt, len, print_fn, fmt_percent); } static int field_cmp(u64 field_a, u64 field_b) @@ -221,11 +221,12 @@ static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) va_list args; ssize_t ssize = hpp->size; double percent; - int ret; + int ret, len; va_start(args, fmt); + len = va_arg(args, int); percent = va_arg(args, double); - ret = value_color_snprintf(hpp->buf, hpp->size, fmt, percent); + ret = percent_color_len_snprintf(hpp->buf, hpp->size, fmt, len, percent); va_end(args); return (ret >= ssize) ? (ssize - 1) : ret; @@ -253,7 +254,7 @@ static u64 he_get_##_field(struct hist_entry *he) \ static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ + return __hpp__fmt(hpp, he, he_get_##_field, " %*.2f%%", 6, \ hpp_color_scnprintf, true); \ } @@ -261,8 +262,8 @@ static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ - return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ + int len = symbol_conf.field_sep ? 1 : 6; \ + return __hpp__fmt(hpp, he, he_get_##_field, " %*.2f%%", len, \ hpp_entry_scnprintf, true); \ } @@ -281,7 +282,7 @@ static u64 he_get_acc_##_field(struct hist_entry *he) \ static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \ + return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %*.2f%%", 6, \ hpp_color_scnprintf, true); \ } @@ -289,8 +290,8 @@ static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ - return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt, \ + int len = symbol_conf.field_sep ? 1 : 6; \ + return __hpp__fmt_acc(hpp, he, he_get_##_field, " %*.2f%%", len, \ hpp_entry_scnprintf, true); \ } @@ -309,8 +310,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ - return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, \ + int len = symbol_conf.field_sep ? 1 : 11; \ + return __hpp__fmt(hpp, he, he_get_raw_##_field, " %*"PRIu64, len, \ hpp_entry_scnprintf, false); \ } diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 87b8672eb413..f4654183d391 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -335,3 +335,19 @@ int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) va_end(args); return value_color_snprintf(bf, size, fmt, percent); } + +int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...) +{ + va_list args; + int len; + double percent; + const char *color; + + va_start(args, fmt); + len = va_arg(args, int); + percent = va_arg(args, double); + va_end(args); + + color = get_percent_color(percent); + return color_snprintf(bf, size, color, fmt, len, percent); +} diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h index 7ff30a62a132..0a594b8a0c26 100644 --- a/tools/perf/util/color.h +++ b/tools/perf/util/color.h @@ -41,6 +41,7 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); int value_color_snprintf(char *bf, size_t size, const char *fmt, double value); int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); +int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...); int percent_color_fprintf(FILE *fp, const char *fmt, double percent); const char *get_percent_color(double percent); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 742f49a85725..13d074db9ef1 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -267,10 +267,10 @@ typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, - hpp_field_fn get_field, const char *fmt, + hpp_field_fn get_field, const char *fmt, int len, hpp_snprint_fn print_fn, bool fmt_percent); int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, - hpp_field_fn get_field, const char *fmt, + hpp_field_fn get_field, const char *fmt, int len, hpp_snprint_fn print_fn, bool fmt_percent); static inline void advance_hpp(struct perf_hpp *hpp, int inc) -- GitLab From e0d66c74b09f5103eef441a98b68056c4dae4cac Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 31 Jul 2014 14:47:37 +0900 Subject: [PATCH 0185/5088] perf tools: Save column length in perf_hpp_fmt Save column length in the hpp format and pass it to print functions. This is a preparation for users to control column width in the output. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1406785662-5534-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 2 +- tools/perf/ui/hist.c | 135 ++++++++++++++++++++++----------- tools/perf/util/hist.h | 2 + tools/perf/util/sort.c | 3 +- 4 files changed, 94 insertions(+), 48 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 02507ba944e3..c1d8d3925fe1 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -849,7 +849,7 @@ static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists) if (perf_hpp__should_skip(fmt)) continue; - /* We need to add the length of the columns header. */ + /* We need to ensure length of the columns header. */ perf_hpp__reset_width(fmt, hists); ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index c6cffbd0b0e1..e28ca972d046 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -110,7 +110,7 @@ int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, { if (!symbol_conf.cumulate_callchain) { return snprintf(hpp->buf, hpp->size, "%*s", - fmt_percent ? 8 : 12, "N/A"); + fmt_percent ? len + 2 : len + 1, "N/A"); } return __hpp__fmt(hpp, he, get_field, fmt, len, print_fn, fmt_percent); @@ -190,32 +190,31 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, return ret; } -#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ -static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ - struct perf_hpp *hpp, \ - struct perf_evsel *evsel) \ -{ \ - int len = _min_width; \ - \ - if (symbol_conf.event_group) \ - len = max(len, evsel->nr_members * _unit_width); \ - \ - return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ -} - -#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ -static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ +#define __HPP_WIDTH_FN(_type, _str) \ +static int hpp__width_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp __maybe_unused, \ struct perf_evsel *evsel) \ { \ - int len = _min_width; \ + int len = fmt->len; \ \ if (symbol_conf.event_group) \ - len = max(len, evsel->nr_members * _unit_width); \ + len = max(len, evsel->nr_members * len); \ + \ + if (len < (int)strlen(_str)) \ + len = strlen(_str); \ \ return len; \ } +#define __HPP_HEADER_FN(_type, _str) \ +static int hpp__header_##_type(struct perf_hpp_fmt *fmt, \ + struct perf_hpp *hpp, \ + struct perf_evsel *evsel) \ +{ \ + int len = hpp__width_##_type(fmt, hpp, evsel); \ + return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ +} + static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) { va_list args; @@ -251,18 +250,19 @@ static u64 he_get_##_field(struct hist_entry *he) \ return he->stat._field; \ } \ \ -static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ +static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - return __hpp__fmt(hpp, he, he_get_##_field, " %*.2f%%", 6, \ + int len = fmt->len - 2; /* 2 for a space and a % sign */ \ + return __hpp__fmt(hpp, he, he_get_##_field, " %*.2f%%", len, \ hpp_color_scnprintf, true); \ } #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ -static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ +static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - int len = symbol_conf.field_sep ? 1 : 6; \ + int len = symbol_conf.field_sep ? 1 : fmt->len - 2; \ return __hpp__fmt(hpp, he, he_get_##_field, " %*.2f%%", len, \ hpp_entry_scnprintf, true); \ } @@ -279,18 +279,19 @@ static u64 he_get_acc_##_field(struct hist_entry *he) \ return he->stat_acc->_field; \ } \ \ -static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ +static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %*.2f%%", 6, \ + int len = fmt->len - 2; /* 2 for a space and a % sign */ \ + return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %*.2f%%", len, \ hpp_color_scnprintf, true); \ } #define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ -static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ +static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - int len = symbol_conf.field_sep ? 1 : 6; \ + int len = symbol_conf.field_sep ? 1 : fmt->len - 2; \ return __hpp__fmt_acc(hpp, he, he_get_##_field, " %*.2f%%", len, \ hpp_entry_scnprintf, true); \ } @@ -307,10 +308,10 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \ return he->stat._field; \ } \ \ -static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ +static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - int len = symbol_conf.field_sep ? 1 : 11; \ + int len = symbol_conf.field_sep ? 1 : fmt->len - 1; \ return __hpp__fmt(hpp, he, he_get_raw_##_field, " %*"PRIu64, len, \ hpp_entry_scnprintf, false); \ } @@ -322,37 +323,38 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ } -#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ -__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ -__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ +#define HPP_PERCENT_FNS(_type, _str, _field) \ +__HPP_WIDTH_FN(_type, _str) \ +__HPP_HEADER_FN(_type, _str) \ __HPP_COLOR_PERCENT_FN(_type, _field) \ __HPP_ENTRY_PERCENT_FN(_type, _field) \ __HPP_SORT_FN(_type, _field) -#define HPP_PERCENT_ACC_FNS(_type, _str, _field, _min_width, _unit_width)\ -__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ -__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ +#define HPP_PERCENT_ACC_FNS(_type, _str, _field) \ +__HPP_WIDTH_FN(_type, _str) \ +__HPP_HEADER_FN(_type, _str) \ __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ __HPP_SORT_ACC_FN(_type, _field) -#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ -__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ -__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ +#define HPP_RAW_FNS(_type, _str, _field) \ +__HPP_WIDTH_FN(_type, _str) \ +__HPP_HEADER_FN(_type, _str) \ __HPP_ENTRY_RAW_FN(_type, _field) \ __HPP_SORT_RAW_FN(_type, _field) -__HPP_HEADER_FN(overhead_self, "Self", 8, 8) +__HPP_WIDTH_FN(overhead_self, "Self") +__HPP_HEADER_FN(overhead_self, "Self") -HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) -HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) -HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) -HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) -HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) -HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8) +HPP_PERCENT_FNS(overhead, "Overhead", period) +HPP_PERCENT_FNS(overhead_sys, "sys", period_sys) +HPP_PERCENT_FNS(overhead_us, "usr", period_us) +HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys) +HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us) +HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period) -HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) -HPP_RAW_FNS(period, "Period", period, 12, 12) +HPP_RAW_FNS(samples, "Samples", nr_events) +HPP_RAW_FNS(period, "Period", period) static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, struct hist_entry *b __maybe_unused) @@ -453,6 +455,8 @@ void perf_hpp__init(void) perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead_self; + perf_hpp__format[PERF_HPP__OVERHEAD].width = + hpp__width_overhead_self; } perf_hpp__column_enable(PERF_HPP__OVERHEAD); @@ -519,6 +523,7 @@ void perf_hpp__cancel_cumulate(void) perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC); perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead; + perf_hpp__format[PERF_HPP__OVERHEAD].width = hpp__width_overhead; } void perf_hpp__setup_output_field(void) @@ -623,3 +628,41 @@ unsigned int hists__sort_list_width(struct hists *hists) return ret; } + +void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) +{ + int idx; + + if (perf_hpp__is_sort_entry(fmt)) + return perf_hpp__reset_sort_width(fmt, hists); + + for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { + if (fmt == &perf_hpp__format[idx]) + break; + } + + if (idx == PERF_HPP__MAX_INDEX) + return; + + switch (idx) { + case PERF_HPP__OVERHEAD: + case PERF_HPP__OVERHEAD_SYS: + case PERF_HPP__OVERHEAD_US: + case PERF_HPP__OVERHEAD_ACC: + fmt->len = 8; + break; + + case PERF_HPP__OVERHEAD_GUEST_SYS: + case PERF_HPP__OVERHEAD_GUEST_US: + fmt->len = 9; + break; + + case PERF_HPP__SAMPLES: + case PERF_HPP__PERIOD: + fmt->len = 12; + break; + + default: + break; + } +} diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 13d074db9ef1..a7ae890f4c71 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -207,6 +207,7 @@ struct perf_hpp_fmt { struct list_head list; struct list_head sort_list; bool elide; + int len; }; extern struct list_head perf_hpp__list; @@ -261,6 +262,7 @@ static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format) } void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); +void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists); typedef u64 (*hpp_field_fn)(struct hist_entry *he); typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index eda9ee836cee..a7f8a7b0eced 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1194,7 +1194,7 @@ bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) return hse_a->se == hse_b->se; } -void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) +void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) { struct hpp_sort_entry *hse; @@ -1265,6 +1265,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd) INIT_LIST_HEAD(&hse->hpp.list); INIT_LIST_HEAD(&hse->hpp.sort_list); hse->hpp.elide = false; + hse->hpp.len = 0; return hse; } -- GitLab From 5b5916696051b88e63f3726cc3db44bf9561bad9 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 31 Jul 2014 14:47:38 +0900 Subject: [PATCH 0186/5088] perf report: Honor column width setting Set column width and do not change it if user gives -w/--column-widths option. It'll truncate longer symbols than the width if exists. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1406785662-5534-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 18 +++++--- tools/perf/ui/gtk/hists.c | 10 ++-- tools/perf/ui/hist.c | 84 +++++++++++++++++++++++----------- tools/perf/ui/stdio/hist.c | 4 +- tools/perf/util/hist.h | 14 +++--- tools/perf/util/sort.c | 49 ++++++++++++-------- 6 files changed, 116 insertions(+), 63 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index c1d8d3925fe1..e07d4e848d5c 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -678,12 +678,12 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \ } \ \ static int \ -hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ +hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ - return __hpp__fmt(hpp, he, __hpp_get_##_field, " %*.2f%%", 6, \ - __hpp__slsmg_color_printf, true); \ + return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \ + __hpp__slsmg_color_printf, true); \ } #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ @@ -693,19 +693,20 @@ static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ } \ \ static int \ -hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ +hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ if (!symbol_conf.cumulate_callchain) { \ + int len = fmt->user_len ?: fmt->len; \ int ret = scnprintf(hpp->buf, hpp->size, \ - "%*s", 8, "N/A"); \ + "%*s", len, "N/A"); \ slsmg_printf("%s", hpp->buf); \ \ return ret; \ } \ - return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %*.2f%%", \ - 6, __hpp__slsmg_color_printf, true); \ + return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \ + " %*.2f%%", __hpp__slsmg_color_printf, true); \ } __HPP_COLOR_PERCENT_FN(overhead, period) @@ -1549,6 +1550,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, memset(options, 0, sizeof(options)); + if (symbol_conf.col_width_list_str) + perf_hpp__set_user_width(symbol_conf.col_width_list_str); + while (1) { const struct thread *thread = NULL; const struct dso *dso = NULL; diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 91f6cd7d2312..897b2e140428 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -41,12 +41,12 @@ static u64 he_get_##_field(struct hist_entry *he) \ return he->stat._field; \ } \ \ -static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ +static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ - return __hpp__fmt(hpp, he, he_get_##_field, " %*.2f%%", 6, \ - __percent_color_snprintf, true); \ + return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ + __percent_color_snprintf, true); \ } #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ @@ -59,8 +59,8 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ - return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %*.2f%%", 6, \ - __percent_color_snprintf, true); \ + return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ + __percent_color_snprintf, true); \ } __HPP_COLOR_PERCENT_FN(overhead, period) diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index e28ca972d046..b2d60a95f01d 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -15,9 +15,9 @@ __ret; \ }) -int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, - hpp_field_fn get_field, const char *fmt, int len, - hpp_snprint_fn print_fn, bool fmt_percent) +static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, + hpp_field_fn get_field, const char *fmt, int len, + hpp_snprint_fn print_fn, bool fmt_percent) { int ret; struct hists *hists = he->hists; @@ -104,16 +104,35 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, return ret; } -int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, - hpp_field_fn get_field, const char *fmt, int len, - hpp_snprint_fn print_fn, bool fmt_percent) +int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he, hpp_field_fn get_field, + const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent) +{ + int len = fmt->user_len ?: fmt->len; + + if (symbol_conf.field_sep) { + return __hpp__fmt(hpp, he, get_field, fmtstr, 1, + print_fn, fmt_percent); + } + + if (fmt_percent) + len -= 2; /* 2 for a space and a % sign */ + else + len -= 1; + + return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent); +} + +int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he, hpp_field_fn get_field, + const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent) { if (!symbol_conf.cumulate_callchain) { - return snprintf(hpp->buf, hpp->size, "%*s", - fmt_percent ? len + 2 : len + 1, "N/A"); + int len = fmt->user_len ?: fmt->len; + return snprintf(hpp->buf, hpp->size, " %*s", len - 1, "N/A"); } - return __hpp__fmt(hpp, he, get_field, fmt, len, print_fn, fmt_percent); + return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmt_percent); } static int field_cmp(u64 field_a, u64 field_b) @@ -195,10 +214,10 @@ static int hpp__width_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp __maybe_unused, \ struct perf_evsel *evsel) \ { \ - int len = fmt->len; \ + int len = fmt->user_len ?: fmt->len; \ \ if (symbol_conf.event_group) \ - len = max(len, evsel->nr_members * len); \ + len = max(len, evsel->nr_members * fmt->len); \ \ if (len < (int)strlen(_str)) \ len = strlen(_str); \ @@ -253,18 +272,16 @@ static u64 he_get_##_field(struct hist_entry *he) \ static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - int len = fmt->len - 2; /* 2 for a space and a % sign */ \ - return __hpp__fmt(hpp, he, he_get_##_field, " %*.2f%%", len, \ - hpp_color_scnprintf, true); \ + return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ + hpp_color_scnprintf, true); \ } #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - int len = symbol_conf.field_sep ? 1 : fmt->len - 2; \ - return __hpp__fmt(hpp, he, he_get_##_field, " %*.2f%%", len, \ - hpp_entry_scnprintf, true); \ + return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ + hpp_entry_scnprintf, true); \ } #define __HPP_SORT_FN(_type, _field) \ @@ -282,18 +299,16 @@ static u64 he_get_acc_##_field(struct hist_entry *he) \ static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - int len = fmt->len - 2; /* 2 for a space and a % sign */ \ - return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %*.2f%%", len, \ - hpp_color_scnprintf, true); \ + return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ + hpp_color_scnprintf, true); \ } #define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - int len = symbol_conf.field_sep ? 1 : fmt->len - 2; \ - return __hpp__fmt_acc(hpp, he, he_get_##_field, " %*.2f%%", len, \ - hpp_entry_scnprintf, true); \ + return hpp__fmt_acc(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ + hpp_entry_scnprintf, true); \ } #define __HPP_SORT_ACC_FN(_type, _field) \ @@ -311,9 +326,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - int len = symbol_conf.field_sep ? 1 : fmt->len - 1; \ - return __hpp__fmt(hpp, he, he_get_raw_##_field, " %*"PRIu64, len, \ - hpp_entry_scnprintf, false); \ + return hpp__fmt(fmt, hpp, he, he_get_raw_##_field, " %*"PRIu64, \ + hpp_entry_scnprintf, false); \ } #define __HPP_SORT_RAW_FN(_type, _field) \ @@ -666,3 +680,21 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) break; } } + +void perf_hpp__set_user_width(const char *width_list_str) +{ + struct perf_hpp_fmt *fmt; + const char *ptr = width_list_str; + + perf_hpp__for_each_format(fmt) { + char *p; + + int len = strtol(ptr, &p, 10); + fmt->user_len = len; + + if (*p == ',') + ptr = p + 1; + else + break; + } +} diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 40af0acb4fe9..15b451acbde6 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -395,10 +395,12 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, init_rem_hits(); - perf_hpp__for_each_format(fmt) perf_hpp__reset_width(fmt, hists); + if (symbol_conf.col_width_list_str) + perf_hpp__set_user_width(symbol_conf.col_width_list_str); + if (!show_header) goto print_entries; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index a7ae890f4c71..2e70003fcd00 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -208,6 +208,7 @@ struct perf_hpp_fmt { struct list_head sort_list; bool elide; int len; + int user_len; }; extern struct list_head perf_hpp__list; @@ -263,17 +264,18 @@ static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format) void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists); +void perf_hpp__set_user_width(const char *width_list_str); typedef u64 (*hpp_field_fn)(struct hist_entry *he); typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); -int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, - hpp_field_fn get_field, const char *fmt, int len, - hpp_snprint_fn print_fn, bool fmt_percent); -int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, - hpp_field_fn get_field, const char *fmt, int len, - hpp_snprint_fn print_fn, bool fmt_percent); +int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he, hpp_field_fn get_field, + const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent); +int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he, hpp_field_fn get_field, + const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent); static inline void advance_hpp(struct perf_hpp *hpp, int inc) { diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index a7f8a7b0eced..153b3803f0b7 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -70,8 +70,10 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { const char *comm = thread__comm_str(he->thread); - return repsep_snprintf(bf, size, "%5d:%-*s", he->thread->tid, - width - 6, comm ?: ""); + + width = max(7U, width) - 6; + return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid, + width, width, comm ?: ""); } struct sort_entry sort_thread = { @@ -106,7 +108,7 @@ sort__comm_sort(struct hist_entry *left, struct hist_entry *right) static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%-*s", width, comm__str(he->comm)); + return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm)); } struct sort_entry sort_comm = { @@ -152,10 +154,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf, if (map && map->dso) { const char *dso_name = !verbose ? map->dso->short_name : map->dso->long_name; - return repsep_snprintf(bf, size, "%-*s", width, dso_name); + return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name); } - return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); + return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]"); } static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf, @@ -257,7 +259,10 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, width - ret, ""); } - return ret; + if (ret > width) + bf[width] = '\0'; + + return width; } static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, @@ -302,10 +307,9 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) } static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, - size_t size, - unsigned int width __maybe_unused) + size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%-s", he->srcline); + return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline); } struct sort_entry sort_srcline = { @@ -332,7 +336,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%-*s", width, + return repsep_snprintf(bf, size, "%-*.*s", width, width, he->parent ? he->parent->name : "[other]"); } @@ -354,7 +358,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - return repsep_snprintf(bf, size, "%*d", width, he->cpu); + return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu); } struct sort_entry sort_cpu = { @@ -484,7 +488,7 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf, else if (he->branch_info->flags.mispred) out = "Y"; - return repsep_snprintf(bf, size, "%-*s", width, out); + return repsep_snprintf(bf, size, "%-*.*s", width, width, out); } /* --sort daddr_sym */ @@ -1210,12 +1214,14 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct perf_evsel *evsel) { struct hpp_sort_entry *hse; - size_t len; + size_t len = fmt->user_len; hse = container_of(fmt, struct hpp_sort_entry, hpp); - len = hists__col_len(&evsel->hists, hse->se->se_width_idx); - return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header); + if (!len) + len = hists__col_len(&evsel->hists, hse->se->se_width_idx); + + return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, hse->se->se_header); } static int __sort__hpp_width(struct perf_hpp_fmt *fmt, @@ -1223,20 +1229,26 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt, struct perf_evsel *evsel) { struct hpp_sort_entry *hse; + size_t len = fmt->user_len; hse = container_of(fmt, struct hpp_sort_entry, hpp); - return hists__col_len(&evsel->hists, hse->se->se_width_idx); + if (!len) + len = hists__col_len(&evsel->hists, hse->se->se_width_idx); + + return len; } static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct hist_entry *he) { struct hpp_sort_entry *hse; - size_t len; + size_t len = fmt->user_len; hse = container_of(fmt, struct hpp_sort_entry, hpp); - len = hists__col_len(he->hists, hse->se->se_width_idx); + + if (!len) + len = hists__col_len(he->hists, hse->se->se_width_idx); return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); } @@ -1266,6 +1278,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd) INIT_LIST_HEAD(&hse->hpp.sort_list); hse->hpp.elide = false; hse->hpp.len = 0; + hse->hpp.user_len = 0; return hse; } -- GitLab From cf59002fdebc9c00ee29233e65bc39dd69e0eaf6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 31 Jul 2014 14:47:39 +0900 Subject: [PATCH 0187/5088] perf top: Add -w option for setting column width Add -w/--column-widths option like perf report does so that users are able to see symbols even with some very long C++ library/functions. It can be a list separated by comma for each column. $ perf top -w 0,20,30 The value of 0 means there's no limit. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1406785662-5534-6-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 2 +- tools/perf/Documentation/perf-top.txt | 6 ++++++ tools/perf/builtin-top.c | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index d2b59af62bc0..d561e0214f52 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -147,7 +147,7 @@ OPTIONS -w:: --column-widths=:: Force each column width to the provided list, for large terminal - readability. + readability. 0 means no limit (default behavior). -t:: --field-separator=:: diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 180ae02137a5..28fdee394880 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt @@ -193,6 +193,12 @@ Default is to monitor all CPUS. sum of shown entries will be always 100%. "absolute" means it retains the original value before and after the filter is applied. +-w:: +--column-widths=:: + Force each column width to the provided list, for large terminal + readability. 0 means no limit (default behavior). + + INTERACTIVE PROMPTING KEYS -------------------------- diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 377971dc89a3..bde216b2071c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1131,6 +1131,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) "Don't show entries under that percent", parse_percent_limit), OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", "How to display percentage of filtered entries", parse_filter_percentage), + OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, + "width[,width...]", + "don't try to adjust column width, use these fixed values"), OPT_END() }; const char * const top_usage[] = { -- GitLab From 1ecd44533a8a724f64d4305abb69836ca73c7390 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 31 Jul 2014 14:47:40 +0900 Subject: [PATCH 0188/5088] perf tools: Add name field into perf_hpp_fmt It makes the code a bit simpler and easier to debug IMHO. I guess it can also remove similar code in perf diff, but let's keep it for a future work. :) Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1406785662-5534-7-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/gtk/hists.c | 4 +- tools/perf/ui/hist.c | 136 +++++++++++++++++--------------------- tools/perf/util/hist.h | 1 + tools/perf/util/sort.c | 6 +- 4 files changed, 66 insertions(+), 81 deletions(-) diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 897b2e140428..f3fa4258b256 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -207,10 +207,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, if (perf_hpp__is_sort_entry(fmt)) sym_col = col_idx; - fmt->header(fmt, &hpp, hists_to_evsel(hists)); - gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), - -1, ltrim(s), + -1, fmt->name, renderer, "markup", col_idx++, NULL); } diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index b2d60a95f01d..b5fa7019d2e2 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -209,29 +209,26 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, return ret; } -#define __HPP_WIDTH_FN(_type, _str) \ -static int hpp__width_##_type(struct perf_hpp_fmt *fmt, \ - struct perf_hpp *hpp __maybe_unused, \ - struct perf_evsel *evsel) \ -{ \ - int len = fmt->user_len ?: fmt->len; \ - \ - if (symbol_conf.event_group) \ - len = max(len, evsel->nr_members * fmt->len); \ - \ - if (len < (int)strlen(_str)) \ - len = strlen(_str); \ - \ - return len; \ -} - -#define __HPP_HEADER_FN(_type, _str) \ -static int hpp__header_##_type(struct perf_hpp_fmt *fmt, \ - struct perf_hpp *hpp, \ - struct perf_evsel *evsel) \ -{ \ - int len = hpp__width_##_type(fmt, hpp, evsel); \ - return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ +static int hpp__width_fn(struct perf_hpp_fmt *fmt, + struct perf_hpp *hpp __maybe_unused, + struct perf_evsel *evsel) +{ + int len = fmt->user_len ?: fmt->len; + + if (symbol_conf.event_group) + len = max(len, evsel->nr_members * fmt->len); + + if (len < (int)strlen(fmt->name)) + len = strlen(fmt->name); + + return len; +} + +static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct perf_evsel *evsel) +{ + int len = hpp__width_fn(fmt, hpp, evsel); + return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); } static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) @@ -337,38 +334,29 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ } -#define HPP_PERCENT_FNS(_type, _str, _field) \ -__HPP_WIDTH_FN(_type, _str) \ -__HPP_HEADER_FN(_type, _str) \ +#define HPP_PERCENT_FNS(_type, _field) \ __HPP_COLOR_PERCENT_FN(_type, _field) \ __HPP_ENTRY_PERCENT_FN(_type, _field) \ __HPP_SORT_FN(_type, _field) -#define HPP_PERCENT_ACC_FNS(_type, _str, _field) \ -__HPP_WIDTH_FN(_type, _str) \ -__HPP_HEADER_FN(_type, _str) \ +#define HPP_PERCENT_ACC_FNS(_type, _field) \ __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ __HPP_SORT_ACC_FN(_type, _field) -#define HPP_RAW_FNS(_type, _str, _field) \ -__HPP_WIDTH_FN(_type, _str) \ -__HPP_HEADER_FN(_type, _str) \ +#define HPP_RAW_FNS(_type, _field) \ __HPP_ENTRY_RAW_FN(_type, _field) \ __HPP_SORT_RAW_FN(_type, _field) -__HPP_WIDTH_FN(overhead_self, "Self") -__HPP_HEADER_FN(overhead_self, "Self") +HPP_PERCENT_FNS(overhead, period) +HPP_PERCENT_FNS(overhead_sys, period_sys) +HPP_PERCENT_FNS(overhead_us, period_us) +HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys) +HPP_PERCENT_FNS(overhead_guest_us, period_guest_us) +HPP_PERCENT_ACC_FNS(overhead_acc, period) -HPP_PERCENT_FNS(overhead, "Overhead", period) -HPP_PERCENT_FNS(overhead_sys, "sys", period_sys) -HPP_PERCENT_FNS(overhead_us, "usr", period_us) -HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys) -HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us) -HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period) - -HPP_RAW_FNS(samples, "Samples", nr_events) -HPP_RAW_FNS(period, "Period", period) +HPP_RAW_FNS(samples, nr_events) +HPP_RAW_FNS(period, period) static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, struct hist_entry *b __maybe_unused) @@ -376,47 +364,50 @@ static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, return 0; } -#define HPP__COLOR_PRINT_FNS(_name) \ +#define HPP__COLOR_PRINT_FNS(_name, _fn) \ { \ - .header = hpp__header_ ## _name, \ - .width = hpp__width_ ## _name, \ - .color = hpp__color_ ## _name, \ - .entry = hpp__entry_ ## _name, \ + .name = _name, \ + .header = hpp__header_fn, \ + .width = hpp__width_fn, \ + .color = hpp__color_ ## _fn, \ + .entry = hpp__entry_ ## _fn, \ .cmp = hpp__nop_cmp, \ .collapse = hpp__nop_cmp, \ - .sort = hpp__sort_ ## _name, \ + .sort = hpp__sort_ ## _fn, \ } -#define HPP__COLOR_ACC_PRINT_FNS(_name) \ +#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn) \ { \ - .header = hpp__header_ ## _name, \ - .width = hpp__width_ ## _name, \ - .color = hpp__color_ ## _name, \ - .entry = hpp__entry_ ## _name, \ + .name = _name, \ + .header = hpp__header_fn, \ + .width = hpp__width_fn, \ + .color = hpp__color_ ## _fn, \ + .entry = hpp__entry_ ## _fn, \ .cmp = hpp__nop_cmp, \ .collapse = hpp__nop_cmp, \ - .sort = hpp__sort_ ## _name, \ + .sort = hpp__sort_ ## _fn, \ } -#define HPP__PRINT_FNS(_name) \ +#define HPP__PRINT_FNS(_name, _fn) \ { \ - .header = hpp__header_ ## _name, \ - .width = hpp__width_ ## _name, \ - .entry = hpp__entry_ ## _name, \ + .name = _name, \ + .header = hpp__header_fn, \ + .width = hpp__width_fn, \ + .entry = hpp__entry_ ## _fn, \ .cmp = hpp__nop_cmp, \ .collapse = hpp__nop_cmp, \ - .sort = hpp__sort_ ## _name, \ + .sort = hpp__sort_ ## _fn, \ } struct perf_hpp_fmt perf_hpp__format[] = { - HPP__COLOR_PRINT_FNS(overhead), - HPP__COLOR_PRINT_FNS(overhead_sys), - HPP__COLOR_PRINT_FNS(overhead_us), - HPP__COLOR_PRINT_FNS(overhead_guest_sys), - HPP__COLOR_PRINT_FNS(overhead_guest_us), - HPP__COLOR_ACC_PRINT_FNS(overhead_acc), - HPP__PRINT_FNS(samples), - HPP__PRINT_FNS(period) + HPP__COLOR_PRINT_FNS("Overhead", overhead), + HPP__COLOR_PRINT_FNS("sys", overhead_sys), + HPP__COLOR_PRINT_FNS("usr", overhead_us), + HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys), + HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us), + HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc), + HPP__PRINT_FNS("Samples", samples), + HPP__PRINT_FNS("Period", period) }; LIST_HEAD(perf_hpp__list); @@ -466,11 +457,7 @@ void perf_hpp__init(void) if (symbol_conf.cumulate_callchain) { perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC); - - perf_hpp__format[PERF_HPP__OVERHEAD].header = - hpp__header_overhead_self; - perf_hpp__format[PERF_HPP__OVERHEAD].width = - hpp__width_overhead_self; + perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self"; } perf_hpp__column_enable(PERF_HPP__OVERHEAD); @@ -536,8 +523,7 @@ void perf_hpp__cancel_cumulate(void) return; perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC); - perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead; - perf_hpp__format[PERF_HPP__OVERHEAD].width = hpp__width_overhead; + perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead"; } void perf_hpp__setup_output_field(void) diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 2e70003fcd00..95405a8fbd95 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -192,6 +192,7 @@ struct perf_hpp { }; struct perf_hpp_fmt { + const char *name; int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, struct perf_evsel *evsel); int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 153b3803f0b7..b4a805e5e440 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1206,8 +1206,7 @@ void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) return; hse = container_of(fmt, struct hpp_sort_entry, hpp); - hists__new_col_len(hists, hse->se->se_width_idx, - strlen(hse->se->se_header)); + hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name)); } static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, @@ -1221,7 +1220,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, if (!len) len = hists__col_len(&evsel->hists, hse->se->se_width_idx); - return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, hse->se->se_header); + return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); } static int __sort__hpp_width(struct perf_hpp_fmt *fmt, @@ -1265,6 +1264,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd) } hse->se = sd->entry; + hse->hpp.name = sd->entry->se_header; hse->hpp.header = __sort__hpp_header; hse->hpp.width = __sort__hpp_width; hse->hpp.entry = __sort__hpp_entry; -- GitLab From 59dc9f2534569d11a55c8b5dbe93c36f2b2fa506 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 31 Jul 2014 14:47:41 +0900 Subject: [PATCH 0189/5088] perf tools: Fix column alignment when headers aren't shown on TUI If user sets ui.show-headers config option to false, it didn't calculate default column width so it broke the alignment. This is because it does the calculation just before showing headers. Move it to the beginning of the hist browser so that it can be called regardless of the config option. Reported-by: Jiri Olsa Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1406785662-5534-8-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e07d4e848d5c..045c1e16ac59 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -850,9 +850,6 @@ static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists) if (perf_hpp__should_skip(fmt)) continue; - /* We need to ensure length of the columns header. */ - perf_hpp__reset_width(fmt, hists); - ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); if (advance_hpp_check(&dummy_hpp, ret)) break; @@ -1501,6 +1498,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, char buf[64]; char script_opt[64]; int delay_secs = hbt ? hbt->refresh : 0; + struct perf_hpp_fmt *fmt; #define HIST_BROWSER_HELP_COMMON \ "h/?/F1 Show this window\n" \ @@ -1550,6 +1548,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, memset(options, 0, sizeof(options)); + perf_hpp__for_each_format(fmt) + perf_hpp__reset_width(fmt, hists); + if (symbol_conf.col_width_list_str) perf_hpp__set_user_width(symbol_conf.col_width_list_str); -- GitLab From 038fa0b9739d7f375f3f61a2ce4f78ad44329f66 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 3 Aug 2014 14:10:36 +0200 Subject: [PATCH 0190/5088] perf tools: Fix PERF_FLAG_FD_CLOEXEC flag probing event type open counters due to EBUSY error We were using PERF_COUNT_SW_CPU_CLOCK as an probing event type. Using expected PERF_TYPE_SOFTWARE type instead. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: William Cohen Cc: Yann Droneaud Link: http://lkml.kernel.org/r/20140803121036.GA1181@krava.brq.redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cloexec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index dede0c388ed4..5073c01af618 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c @@ -9,7 +9,7 @@ static int perf_flag_probe(void) { /* use 'safest' configuration as used in perf_evsel__fallback() */ struct perf_event_attr attr = { - .type = PERF_COUNT_SW_CPU_CLOCK, + .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_CLOCK, }; int fd; -- GitLab From d6a947fb6cdff3a19db93895c746f70b5903a965 Mon Sep 17 00:00:00 2001 From: Thomas Ilsche Date: Mon, 4 Aug 2014 15:03:15 +0200 Subject: [PATCH 0191/5088] perf tools: Default to python version 2 According to PEP 394 recommendation [1], it's more portable to use python2 rather than plain python to refer python binary version 2. Since there're distros using python3 by default like Arch, and we don't support python3 (yet), it'd be better using python2 explicitly. But older versions (prior to 2.7) seem not to provide python2 but just python. Given that it's only old version, try python2 first and then fallback to python. It'll ensure that it always points to python 2.x. I tested (compiles and perf script runs) with the combinations: 1) python -> python2.x, python-config -> python2.x-config python2 N/A, python2-config N/A 2) python -> python3.x, python-config -> python3.x-config python2 -> python2.x, python2-config -> python2.x-config 3) python -> python2.x, python-config -> python2.x-config python2 -> python2.x, python2-config -> python2.x-config 4) python -> python2.x, python-config -> python2.x-config python2 -> python2.x, python2-config N/A Based on / replaces the patch 2/2 by Namhyung Kim. [1] https://www.python.org/dev/peps/pep-0394 Based-on-patch-by: Namhyung Kim Signed-off-by: Thomas Ilsche Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/53DF8493.6070206@tu-dresden.de Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/config/Makefile | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index e05d8f99424d..75d4c237b03d 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -121,10 +121,16 @@ ifdef PARSER_DEBUG endif ifndef NO_LIBPYTHON - override PYTHON := \ - $(call get-executable-or-default,PYTHON,python) + # Try different combinations to accommodate systems that only have + # python[2][-config] in weird combinations but always preferring + # python2 and python2-config as per pep-0394. If we catch a + # python[-config] in version 3, the version check will kill it. + PYTHON2 := $(if $(call get-executable,python2),python2,python) + override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2)) + PYTHON2_CONFIG := \ + $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config) override PYTHON_CONFIG := \ - $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config) + $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG)) PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) -- GitLab From 0f7c29ce90c4d20c23de5657e1e2c2eabf51d69a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 30 Jul 2014 12:08:56 +0200 Subject: [PATCH 0192/5088] perf/x86/intel: Update Intel models The model number descriptions got a bit messy, clean them up. Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Link: http://lkml.kernel.org/n/tip-oo3xclxdoy8s7ubssn929vaj@git.kernel.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel.c | 51 +++++++++++++------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 2502d0d9d246..38d1f6d024ff 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -2367,15 +2367,15 @@ __init int intel_pmu_init(void) * Install the hw-cache-events table: */ switch (boot_cpu_data.x86_model) { - case 14: /* 65 nm core solo/duo, "Yonah" */ + case 14: /* 65nm Core "Yonah" */ pr_cont("Core events, "); break; - case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */ + case 15: /* 65nm Core2 "Merom" */ x86_add_quirk(intel_clovertown_quirk); - case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */ - case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */ - case 29: /* six-core 45 nm xeon "Dunnington" */ + case 22: /* 65nm Core2 "Merom-L" */ + case 23: /* 45nm Core2 "Penryn" */ + case 29: /* 45nm Core2 "Dunnington (MP) */ memcpy(hw_cache_event_ids, core2_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -2386,9 +2386,9 @@ __init int intel_pmu_init(void) pr_cont("Core2 events, "); break; - case 26: /* 45 nm nehalem, "Bloomfield" */ - case 30: /* 45 nm nehalem, "Lynnfield" */ - case 46: /* 45 nm nehalem-ex, "Beckton" */ + case 30: /* 45nm Nehalem */ + case 26: /* 45nm Nehalem-EP */ + case 46: /* 45nm Nehalem-EX */ memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, @@ -2415,11 +2415,11 @@ __init int intel_pmu_init(void) pr_cont("Nehalem events, "); break; - case 28: /* Atom */ - case 38: /* Lincroft */ - case 39: /* Penwell */ - case 53: /* Cloverview */ - case 54: /* Cedarview */ + case 28: /* 45nm Atom "Pineview" */ + case 38: /* 45nm Atom "Lincroft" */ + case 39: /* 32nm Atom "Penwell" */ + case 53: /* 32nm Atom "Cloverview" */ + case 54: /* 32nm Atom "Cedarview" */ memcpy(hw_cache_event_ids, atom_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -2430,8 +2430,8 @@ __init int intel_pmu_init(void) pr_cont("Atom events, "); break; - case 55: /* Atom 22nm "Silvermont" */ - case 77: /* Avoton "Silvermont" */ + case 55: /* 22nm Atom "Silvermont" */ + case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */ memcpy(hw_cache_event_ids, slm_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs, @@ -2446,9 +2446,9 @@ __init int intel_pmu_init(void) pr_cont("Silvermont events, "); break; - case 37: /* 32 nm nehalem, "Clarkdale" */ - case 44: /* 32 nm nehalem, "Gulftown" */ - case 47: /* 32 nm Xeon E7 */ + case 37: /* 32nm Westmere */ + case 44: /* 32nm Westmere-EP */ + case 47: /* 32nm Westmere-EX */ memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, @@ -2474,8 +2474,8 @@ __init int intel_pmu_init(void) pr_cont("Westmere events, "); break; - case 42: /* SandyBridge */ - case 45: /* SandyBridge, "Romely-EP" */ + case 42: /* 32nm SandyBridge */ + case 45: /* 32nm SandyBridge-E/EN/EP */ x86_add_quirk(intel_sandybridge_quirk); memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -2506,8 +2506,9 @@ __init int intel_pmu_init(void) pr_cont("SandyBridge events, "); break; - case 58: /* IvyBridge */ - case 62: /* IvyBridge EP */ + + case 58: /* 22nm IvyBridge */ + case 62: /* 22nm IvyBridge-EP/EX */ memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids)); /* dTLB-load-misses on IVB is different than SNB */ @@ -2539,11 +2540,11 @@ __init int intel_pmu_init(void) break; - case 60: /* Haswell Client */ - case 70: - case 71: + case 60: /* 22nm Haswell */ case 63: case 69: + case 70: + case 71: x86_pmu.late_ack = true; memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); -- GitLab From f86977620ee4635f26befcf436700493a38ce002 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 1 Aug 2014 14:33:01 +0200 Subject: [PATCH 0193/5088] perf: Set owner pointer for kernel events Adding fake EVENT_OWNER_KERNEL owner pointer value for kernel perf events, so we could distinguish it from user events, which needs special care in following patch. Signed-off-by: Jiri Olsa Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Mark Rutland Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Mark Rutland Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1406896382-18404-3-git-send-email-jolsa@kernel.org Signed-off-by: Ingo Molnar --- kernel/events/core.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 1cf24b3e42ec..bbb3ca22f07c 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -119,6 +119,13 @@ static int cpu_function_call(int cpu, int (*func) (void *info), void *info) return data.ret; } +#define EVENT_OWNER_KERNEL ((void *) -1) + +static bool is_kernel_event(struct perf_event *event) +{ + return event->owner == EVENT_OWNER_KERNEL; +} + #define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\ PERF_FLAG_FD_OUTPUT |\ PERF_FLAG_PID_CGROUP |\ @@ -3312,16 +3319,12 @@ static void free_event(struct perf_event *event) } /* - * Called when the last reference to the file is gone. + * Remove user event from the owner task. */ -static void put_event(struct perf_event *event) +static void perf_remove_from_owner(struct perf_event *event) { - struct perf_event_context *ctx = event->ctx; struct task_struct *owner; - if (!atomic_long_dec_and_test(&event->refcount)) - return; - rcu_read_lock(); owner = ACCESS_ONCE(event->owner); /* @@ -3354,6 +3357,20 @@ static void put_event(struct perf_event *event) mutex_unlock(&owner->perf_event_mutex); put_task_struct(owner); } +} + +/* + * Called when the last reference to the file is gone. + */ +static void put_event(struct perf_event *event) +{ + struct perf_event_context *ctx = event->ctx; + + if (!atomic_long_dec_and_test(&event->refcount)) + return; + + if (!is_kernel_event(event)) + perf_remove_from_owner(event); WARN_ON_ONCE(ctx->parent_ctx); /* @@ -7366,6 +7383,9 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, goto err; } + /* Mark owner so we could distinguish it from user events. */ + event->owner = EVENT_OWNER_KERNEL; + account_event(event); ctx = find_get_context(event->pmu, task, cpu); -- GitLab From fadfe7be6e50de7f03913833b33c56cd8fb66bac Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 1 Aug 2014 14:33:02 +0200 Subject: [PATCH 0194/5088] perf: Add queued work to remove orphaned child events In cases when the owner task exits before the workload and the workload made some forks, all the events stay in until the last workload process exits. Thats' because each child event holds parent reference. We want to release all children events once the parent is gone, because at that time there's no process to read them anyway, so they're just eating resources. This removal races with process exit, which removes all events and fork, which clone events. To be clear of those two, adding work queue to remove orphaned child for context in case such event is detected. Using delayed work queue (with delay == 1), because we queue this work under perf scheduler callbacks. Normal work queue tries to wake up the queue process, which deadlocks on rq->lock in this place. Also preventing clones from abandoned parent event. Signed-off-by: Jiri Olsa Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Mark Rutland Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Mark Rutland Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1406896382-18404-4-git-send-email-jolsa@kernel.org Signed-off-by: Ingo Molnar --- include/linux/perf_event.h | 4 ++ kernel/events/core.c | 87 +++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 707617a8c0f6..ef5b62bdb103 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -52,6 +52,7 @@ struct perf_guest_info_callbacks { #include #include #include +#include #include struct perf_callchain_entry { @@ -507,6 +508,9 @@ struct perf_event_context { int nr_cgroups; /* cgroup evts */ int nr_branch_stack; /* branch_stack evt */ struct rcu_head rcu_head; + + struct delayed_work orphans_remove; + bool orphans_remove_sched; }; /* diff --git a/kernel/events/core.c b/kernel/events/core.c index bbb3ca22f07c..a25460559b4f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -46,6 +46,8 @@ #include +static struct workqueue_struct *perf_wq; + struct remote_function_call { struct task_struct *p; int (*func)(void *info); @@ -1381,6 +1383,45 @@ static void perf_group_detach(struct perf_event *event) perf_event__header_size(tmp); } +/* + * User event without the task. + */ +static bool is_orphaned_event(struct perf_event *event) +{ + return event && !is_kernel_event(event) && !event->owner; +} + +/* + * Event has a parent but parent's task finished and it's + * alive only because of children holding refference. + */ +static bool is_orphaned_child(struct perf_event *event) +{ + return is_orphaned_event(event->parent); +} + +static void orphans_remove_work(struct work_struct *work); + +static void schedule_orphans_remove(struct perf_event_context *ctx) +{ + if (!ctx->task || ctx->orphans_remove_sched || !perf_wq) + return; + + if (queue_delayed_work(perf_wq, &ctx->orphans_remove, 1)) { + get_ctx(ctx); + ctx->orphans_remove_sched = true; + } +} + +static int __init perf_workqueue_init(void) +{ + perf_wq = create_singlethread_workqueue("perf"); + WARN(!perf_wq, "failed to create perf workqueue\n"); + return perf_wq ? 0 : -1; +} + +core_initcall(perf_workqueue_init); + static inline int event_filter_match(struct perf_event *event) { @@ -1430,6 +1471,9 @@ event_sched_out(struct perf_event *event, if (event->attr.exclusive || !cpuctx->active_oncpu) cpuctx->exclusive = 0; + if (is_orphaned_child(event)) + schedule_orphans_remove(ctx); + perf_pmu_enable(event->pmu); } @@ -1732,6 +1776,9 @@ event_sched_in(struct perf_event *event, if (event->attr.exclusive) cpuctx->exclusive = 1; + if (is_orphaned_child(event)) + schedule_orphans_remove(ctx); + out: perf_pmu_enable(event->pmu); @@ -3074,6 +3121,7 @@ static void __perf_event_init_context(struct perf_event_context *ctx) INIT_LIST_HEAD(&ctx->flexible_groups); INIT_LIST_HEAD(&ctx->event_list); atomic_set(&ctx->refcount, 1); + INIT_DELAYED_WORK(&ctx->orphans_remove, orphans_remove_work); } static struct perf_event_context * @@ -3405,6 +3453,42 @@ static int perf_release(struct inode *inode, struct file *file) return 0; } +/* + * Remove all orphanes events from the context. + */ +static void orphans_remove_work(struct work_struct *work) +{ + struct perf_event_context *ctx; + struct perf_event *event, *tmp; + + ctx = container_of(work, struct perf_event_context, + orphans_remove.work); + + mutex_lock(&ctx->mutex); + list_for_each_entry_safe(event, tmp, &ctx->event_list, event_entry) { + struct perf_event *parent_event = event->parent; + + if (!is_orphaned_child(event)) + continue; + + perf_remove_from_context(event, true); + + mutex_lock(&parent_event->child_mutex); + list_del_init(&event->child_list); + mutex_unlock(&parent_event->child_mutex); + + free_event(event); + put_event(parent_event); + } + + raw_spin_lock_irq(&ctx->lock); + ctx->orphans_remove_sched = false; + raw_spin_unlock_irq(&ctx->lock); + mutex_unlock(&ctx->mutex); + + put_ctx(ctx); +} + u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) { struct perf_event *child; @@ -7709,7 +7793,8 @@ inherit_event(struct perf_event *parent_event, if (IS_ERR(child_event)) return child_event; - if (!atomic_long_inc_not_zero(&parent_event->refcount)) { + if (is_orphaned_event(parent_event) || + !atomic_long_inc_not_zero(&parent_event->refcount)) { free_event(child_event); return NULL; } -- GitLab From 514b2346df385fce61cefb940813207758648136 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 30 Jul 2014 15:22:12 +0800 Subject: [PATCH 0195/5088] perf/x86/uncore: Declare some functions and variables Prepare for moving hardware specific code to seperate files. Signed-off-by: Yan, Zheng Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Stephane Eranian Cc: eranian@google.com Cc: andi@firstfloor.org Link: http://lkml.kernel.org/r/1406704935-27708-1-git-send-email-zheng.z.yan@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 149 +++++++++--------- arch/x86/kernel/cpu/perf_event_intel_uncore.h | 32 ++-- 2 files changed, 98 insertions(+), 83 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index cfc6f9dfcd90..cfe235334b3c 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -1,24 +1,33 @@ #include "perf_event_intel_uncore.h" static struct intel_uncore_type *empty_uncore[] = { NULL, }; -static struct intel_uncore_type **msr_uncores = empty_uncore; -static struct intel_uncore_type **pci_uncores = empty_uncore; -/* pci bus to socket mapping */ -static int pcibus_to_physid[256] = { [0 ... 255] = -1, }; +struct intel_uncore_type **uncore_msr_uncores = empty_uncore; +struct intel_uncore_type **uncore_pci_uncores = empty_uncore; -static struct pci_dev *extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX]; +static bool pcidrv_registered; +struct pci_driver *uncore_pci_driver; +/* pci bus to socket mapping */ +int uncore_pcibus_to_physid[256] = { [0 ... 255] = -1, }; +struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX]; static DEFINE_RAW_SPINLOCK(uncore_box_lock); - /* mask of cpus that collect uncore events */ static cpumask_t uncore_cpu_mask; /* constraint for the fixed counter */ -static struct event_constraint constraint_fixed = +static struct event_constraint uncore_constraint_fixed = EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL); -static struct event_constraint constraint_empty = +struct event_constraint uncore_constraint_empty = EVENT_CONSTRAINT(0, 0, 0); +ssize_t uncore_event_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct uncore_event_desc *event = + container_of(attr, struct uncore_event_desc, attr); + return sprintf(buf, "%s", event->config); +} + #define __BITS_VALUE(x, i, n) ((typeof(x))(((x) >> ((i) * (n))) & \ ((1ULL << (n)) - 1))) @@ -66,18 +75,12 @@ DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4"); DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31"); DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63"); -static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box); -static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box); -static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event); -static void uncore_pmu_event_read(struct perf_event *event); - -static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event) +struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event) { return container_of(event->pmu, struct intel_uncore_pmu, pmu); } -static struct intel_uncore_box * -uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu) +struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu) { struct intel_uncore_box *box; @@ -98,7 +101,7 @@ uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu) return *per_cpu_ptr(pmu->box, cpu); } -static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event) +struct intel_uncore_box *uncore_event_to_box(struct perf_event *event) { /* * perf core schedules event on the basis of cpu, uncore events are @@ -107,7 +110,7 @@ static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event) return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id()); } -static u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event) +u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event) { u64 count; @@ -119,7 +122,7 @@ static u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_eve /* * generic get constraint function for shared match/mask registers. */ -static struct event_constraint * +struct event_constraint * uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event) { struct intel_uncore_extra_reg *er; @@ -154,10 +157,10 @@ uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event) return NULL; } - return &constraint_empty; + return &uncore_constraint_empty; } -static void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event) +void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event) { struct intel_uncore_extra_reg *er; struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; @@ -178,7 +181,7 @@ static void uncore_put_constraint(struct intel_uncore_box *box, struct perf_even reg1->alloc = 0; } -static u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx) +u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx) { struct intel_uncore_extra_reg *er; unsigned long flags; @@ -627,7 +630,7 @@ __snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *eve if (alloc & (0x1 << i)) atomic_sub(1 << (i * 6), &er->ref); } - return &constraint_empty; + return &uncore_constraint_empty; } static u64 snbep_cbox_filter_mask(int fields) @@ -746,7 +749,7 @@ snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event) config1 = snbep_pcu_alter_er(event, idx, false); goto again; } - return &constraint_empty; + return &uncore_constraint_empty; } if (!uncore_box_is_fake(box)) { @@ -841,7 +844,7 @@ static void snbep_qpi_enable_event(struct intel_uncore_box *box, struct perf_eve if (reg1->idx != EXTRA_REG_NONE) { int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER; - struct pci_dev *filter_pdev = extra_pci_dev[box->phys_id][idx]; + struct pci_dev *filter_pdev = uncore_extra_pci_dev[box->phys_id][idx]; WARN_ON_ONCE(!filter_pdev); if (filter_pdev) { pci_write_config_dword(filter_pdev, reg1->reg, @@ -1035,7 +1038,7 @@ static int snbep_pci2phy_map_init(int devid) */ for (i = 0; i < 8; i++) { if (nodeid == ((config >> (3 * i)) & 0x7)) { - pcibus_to_physid[bus] = i; + uncore_pcibus_to_physid[bus] = i; break; } } @@ -1048,10 +1051,10 @@ static int snbep_pci2phy_map_init(int devid) */ i = -1; for (bus = 255; bus >= 0; bus--) { - if (pcibus_to_physid[bus] >= 0) - i = pcibus_to_physid[bus]; + if (uncore_pcibus_to_physid[bus] >= 0) + i = uncore_pcibus_to_physid[bus]; else - pcibus_to_physid[bus] = i; + uncore_pcibus_to_physid[bus] = i; } } @@ -1939,7 +1942,7 @@ static int snb_pci2phy_map_init(int devid) bus = dev->bus->number; - pcibus_to_physid[bus] = 0; + uncore_pcibus_to_physid[bus] = 0; pci_dev_put(dev); @@ -2639,7 +2642,7 @@ nhmex_mbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event nhmex_mbox_put_shared_reg(box, idx[0]); if (alloc & 0x2) nhmex_mbox_put_shared_reg(box, idx[1]); - return &constraint_empty; + return &uncore_constraint_empty; } static void nhmex_mbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event) @@ -2963,7 +2966,7 @@ nhmex_rbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event } return NULL; } - return &constraint_empty; + return &uncore_constraint_empty; } static void nhmex_rbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event) @@ -3140,7 +3143,7 @@ static void uncore_assign_hw_event(struct intel_uncore_box *box, struct perf_eve hwc->event_base = uncore_perf_ctr(box, hwc->idx); } -static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event) +void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event) { u64 prev_count, new_count, delta; int shift; @@ -3201,14 +3204,14 @@ static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer) return HRTIMER_RESTART; } -static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box) +void uncore_pmu_start_hrtimer(struct intel_uncore_box *box) { __hrtimer_start_range_ns(&box->hrtimer, ns_to_ktime(box->hrtimer_duration), 0, HRTIMER_MODE_REL_PINNED, 0); } -static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box) +void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box) { hrtimer_cancel(&box->hrtimer); } @@ -3291,7 +3294,7 @@ uncore_get_event_constraint(struct intel_uncore_box *box, struct perf_event *eve } if (event->attr.config == UNCORE_FIXED_EVENT) - return &constraint_fixed; + return &uncore_constraint_fixed; if (type->constraints) { for_each_event_constraint(c, type->constraints) { @@ -3496,7 +3499,7 @@ static void uncore_pmu_event_del(struct perf_event *event, int flags) event->hw.last_tag = ~0ULL; } -static void uncore_pmu_event_read(struct perf_event *event) +void uncore_pmu_event_read(struct perf_event *event) { struct intel_uncore_box *box = uncore_event_to_box(event); uncore_perf_event_update(box, event); @@ -3758,9 +3761,6 @@ static int __init uncore_types_init(struct intel_uncore_type **types) return ret; } -static struct pci_driver *uncore_pci_driver; -static bool pcidrv_registered; - /* * add a pci uncore device */ @@ -3771,17 +3771,18 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id struct intel_uncore_type *type; int phys_id; - phys_id = pcibus_to_physid[pdev->bus->number]; + phys_id = uncore_pcibus_to_physid[pdev->bus->number]; if (phys_id < 0) return -ENODEV; if (UNCORE_PCI_DEV_TYPE(id->driver_data) == UNCORE_EXTRA_PCI_DEV) { - extra_pci_dev[phys_id][UNCORE_PCI_DEV_IDX(id->driver_data)] = pdev; + int idx = UNCORE_PCI_DEV_IDX(id->driver_data); + uncore_extra_pci_dev[phys_id][idx] = pdev; pci_set_drvdata(pdev, NULL); return 0; } - type = pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)]; + type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)]; box = uncore_alloc_box(type, NUMA_NO_NODE); if (!box) return -ENOMEM; @@ -3813,13 +3814,13 @@ static void uncore_pci_remove(struct pci_dev *pdev) { struct intel_uncore_box *box = pci_get_drvdata(pdev); struct intel_uncore_pmu *pmu; - int i, cpu, phys_id = pcibus_to_physid[pdev->bus->number]; + int i, cpu, phys_id = uncore_pcibus_to_physid[pdev->bus->number]; box = pci_get_drvdata(pdev); if (!box) { for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) { - if (extra_pci_dev[phys_id][i] == pdev) { - extra_pci_dev[phys_id][i] = NULL; + if (uncore_extra_pci_dev[phys_id][i] == pdev) { + uncore_extra_pci_dev[phys_id][i] = NULL; break; } } @@ -3857,28 +3858,28 @@ static int __init uncore_pci_init(void) ret = snbep_pci2phy_map_init(0x3ce0); if (ret) return ret; - pci_uncores = snbep_pci_uncores; + uncore_pci_uncores = snbep_pci_uncores; uncore_pci_driver = &snbep_uncore_pci_driver; break; case 62: /* IvyTown */ ret = snbep_pci2phy_map_init(0x0e1e); if (ret) return ret; - pci_uncores = ivt_pci_uncores; + uncore_pci_uncores = ivt_pci_uncores; uncore_pci_driver = &ivt_uncore_pci_driver; break; case 42: /* Sandy Bridge */ ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_SNB_IMC); if (ret) return ret; - pci_uncores = snb_pci_uncores; + uncore_pci_uncores = snb_pci_uncores; uncore_pci_driver = &snb_uncore_pci_driver; break; case 58: /* Ivy Bridge */ ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_IVB_IMC); if (ret) return ret; - pci_uncores = snb_pci_uncores; + uncore_pci_uncores = snb_pci_uncores; uncore_pci_driver = &ivb_uncore_pci_driver; break; case 60: /* Haswell */ @@ -3886,14 +3887,14 @@ static int __init uncore_pci_init(void) ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_HSW_IMC); if (ret) return ret; - pci_uncores = snb_pci_uncores; + uncore_pci_uncores = snb_pci_uncores; uncore_pci_driver = &hsw_uncore_pci_driver; break; default: return 0; } - ret = uncore_types_init(pci_uncores); + ret = uncore_types_init(uncore_pci_uncores); if (ret) return ret; @@ -3904,7 +3905,7 @@ static int __init uncore_pci_init(void) if (ret == 0) pcidrv_registered = true; else - uncore_types_exit(pci_uncores); + uncore_types_exit(uncore_pci_uncores); return ret; } @@ -3914,7 +3915,7 @@ static void __init uncore_pci_exit(void) if (pcidrv_registered) { pcidrv_registered = false; pci_unregister_driver(uncore_pci_driver); - uncore_types_exit(pci_uncores); + uncore_types_exit(uncore_pci_uncores); } } @@ -3940,8 +3941,8 @@ static void uncore_cpu_dying(int cpu) struct intel_uncore_box *box; int i, j; - for (i = 0; msr_uncores[i]; i++) { - type = msr_uncores[i]; + for (i = 0; uncore_msr_uncores[i]; i++) { + type = uncore_msr_uncores[i]; for (j = 0; j < type->num_boxes; j++) { pmu = &type->pmus[j]; box = *per_cpu_ptr(pmu->box, cpu); @@ -3961,8 +3962,8 @@ static int uncore_cpu_starting(int cpu) phys_id = topology_physical_package_id(cpu); - for (i = 0; msr_uncores[i]; i++) { - type = msr_uncores[i]; + for (i = 0; uncore_msr_uncores[i]; i++) { + type = uncore_msr_uncores[i]; for (j = 0; j < type->num_boxes; j++) { pmu = &type->pmus[j]; box = *per_cpu_ptr(pmu->box, cpu); @@ -4002,8 +4003,8 @@ static int uncore_cpu_prepare(int cpu, int phys_id) struct intel_uncore_box *box; int i, j; - for (i = 0; msr_uncores[i]; i++) { - type = msr_uncores[i]; + for (i = 0; uncore_msr_uncores[i]; i++) { + type = uncore_msr_uncores[i]; for (j = 0; j < type->num_boxes; j++) { pmu = &type->pmus[j]; if (pmu->func_id < 0) @@ -4083,8 +4084,8 @@ static void uncore_event_exit_cpu(int cpu) if (target >= 0) cpumask_set_cpu(target, &uncore_cpu_mask); - uncore_change_context(msr_uncores, cpu, target); - uncore_change_context(pci_uncores, cpu, target); + uncore_change_context(uncore_msr_uncores, cpu, target); + uncore_change_context(uncore_pci_uncores, cpu, target); } static void uncore_event_init_cpu(int cpu) @@ -4099,8 +4100,8 @@ static void uncore_event_init_cpu(int cpu) cpumask_set_cpu(cpu, &uncore_cpu_mask); - uncore_change_context(msr_uncores, -1, cpu); - uncore_change_context(pci_uncores, -1, cpu); + uncore_change_context(uncore_msr_uncores, -1, cpu); + uncore_change_context(uncore_pci_uncores, -1, cpu); } static int uncore_cpu_notifier(struct notifier_block *self, @@ -4168,18 +4169,18 @@ static int __init uncore_cpu_init(void) case 30: case 37: /* Westmere */ case 44: - msr_uncores = nhm_msr_uncores; + uncore_msr_uncores = nhm_msr_uncores; break; case 42: /* Sandy Bridge */ case 58: /* Ivy Bridge */ if (snb_uncore_cbox.num_boxes > max_cores) snb_uncore_cbox.num_boxes = max_cores; - msr_uncores = snb_msr_uncores; + uncore_msr_uncores = snb_msr_uncores; break; case 45: /* Sandy Bridge-EP */ if (snbep_uncore_cbox.num_boxes > max_cores) snbep_uncore_cbox.num_boxes = max_cores; - msr_uncores = snbep_msr_uncores; + uncore_msr_uncores = snbep_msr_uncores; break; case 46: /* Nehalem-EX */ uncore_nhmex = true; @@ -4188,19 +4189,19 @@ static int __init uncore_cpu_init(void) nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events; if (nhmex_uncore_cbox.num_boxes > max_cores) nhmex_uncore_cbox.num_boxes = max_cores; - msr_uncores = nhmex_msr_uncores; + uncore_msr_uncores = nhmex_msr_uncores; break; case 62: /* IvyTown */ if (ivt_uncore_cbox.num_boxes > max_cores) ivt_uncore_cbox.num_boxes = max_cores; - msr_uncores = ivt_msr_uncores; + uncore_msr_uncores = ivt_msr_uncores; break; default: return 0; } - ret = uncore_types_init(msr_uncores); + ret = uncore_types_init(uncore_msr_uncores); if (ret) return ret; @@ -4213,16 +4214,16 @@ static int __init uncore_pmus_register(void) struct intel_uncore_type *type; int i, j; - for (i = 0; msr_uncores[i]; i++) { - type = msr_uncores[i]; + for (i = 0; uncore_msr_uncores[i]; i++) { + type = uncore_msr_uncores[i]; for (j = 0; j < type->num_boxes; j++) { pmu = &type->pmus[j]; uncore_pmu_register(pmu); } } - for (i = 0; pci_uncores[i]; i++) { - type = pci_uncores[i]; + for (i = 0; uncore_pci_uncores[i]; i++) { + type = uncore_pci_uncores[i]; for (j = 0; j < type->num_boxes; j++) { pmu = &type->pmus[j]; uncore_pmu_register(pmu); diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index 90236f0c94a9..e5b5fd7554af 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -505,6 +505,9 @@ struct uncore_event_desc { const char *config; }; +ssize_t uncore_event_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + #define INTEL_UNCORE_EVENT_DESC(_name, _config) \ { \ .attr = __ATTR(_name, 0444, uncore_event_show, NULL), \ @@ -522,15 +525,6 @@ static ssize_t __uncore_##_var##_show(struct kobject *kobj, \ static struct kobj_attribute format_attr_##_var = \ __ATTR(_name, 0444, __uncore_##_var##_show, NULL) - -static ssize_t uncore_event_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct uncore_event_desc *event = - container_of(attr, struct uncore_event_desc, attr); - return sprintf(buf, "%s", event->config); -} - static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box) { return box->pmu->type->box_ctl; @@ -694,3 +688,23 @@ static inline bool uncore_box_is_fake(struct intel_uncore_box *box) { return (box->phys_id < 0); } + +struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event); +struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu); +struct intel_uncore_box *uncore_event_to_box(struct perf_event *event); +u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event); +void uncore_pmu_start_hrtimer(struct intel_uncore_box *box); +void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box); +void uncore_pmu_event_read(struct perf_event *event); +void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event); +struct event_constraint * +uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event); +void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event); +u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx); + +extern struct intel_uncore_type **uncore_msr_uncores; +extern struct intel_uncore_type **uncore_pci_uncores; +extern struct pci_driver *uncore_pci_driver; +extern int uncore_pcibus_to_physid[256]; +extern struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX]; +extern struct event_constraint uncore_constraint_empty; -- GitLab From 92807ffdf32c380a09cfa396c853e97303826103 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 30 Jul 2014 15:22:13 +0800 Subject: [PATCH 0196/5088] perf/x86/uncore: Move NHM/SNB/IVB specific code to seperate file Signed-off-by: Yan, Zheng Signed-off-by: Peter Zijlstra Cc: Andi Kleen Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Stephane Eranian Cc: eranian@google.com Link: http://lkml.kernel.org/r/1406704935-27708-2-git-send-email-zheng.z.yan@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/Makefile | 3 +- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 531 +-------------- arch/x86/kernel/cpu/perf_event_intel_uncore.h | 56 +- .../kernel/cpu/perf_event_intel_uncore_snb.c | 603 ++++++++++++++++++ 4 files changed, 620 insertions(+), 573 deletions(-) create mode 100644 arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 7fd54f09b011..5ca8f4a39106 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -36,7 +36,8 @@ obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd_iommu.o endif obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o -obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o perf_event_intel_rapl.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o perf_event_intel_uncore_snb.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_rapl.o endif diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index cfe235334b3c..feb085c8ca4e 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -37,8 +37,6 @@ DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19"); DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); -DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28"); -DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31"); DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31"); DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28"); DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15"); @@ -1605,508 +1603,6 @@ static struct pci_driver ivt_uncore_pci_driver = { }; /* end of IvyTown uncore support */ -/* Sandy Bridge uncore support */ -static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - - if (hwc->idx < UNCORE_PMC_IDX_FIXED) - wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN); - else - wrmsrl(hwc->config_base, SNB_UNC_CTL_EN); -} - -static void snb_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - wrmsrl(event->hw.config_base, 0); -} - -static void snb_uncore_msr_init_box(struct intel_uncore_box *box) -{ - if (box->pmu->pmu_idx == 0) { - wrmsrl(SNB_UNC_PERF_GLOBAL_CTL, - SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL); - } -} - -static struct uncore_event_desc snb_uncore_events[] = { - INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"), - { /* end: all zeroes */ }, -}; - -static struct attribute *snb_uncore_formats_attr[] = { - &format_attr_event.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_inv.attr, - &format_attr_cmask5.attr, - NULL, -}; - -static struct attribute_group snb_uncore_format_group = { - .name = "format", - .attrs = snb_uncore_formats_attr, -}; - -static struct intel_uncore_ops snb_uncore_msr_ops = { - .init_box = snb_uncore_msr_init_box, - .disable_event = snb_uncore_msr_disable_event, - .enable_event = snb_uncore_msr_enable_event, - .read_counter = uncore_msr_read_counter, -}; - -static struct event_constraint snb_uncore_cbox_constraints[] = { - UNCORE_EVENT_CONSTRAINT(0x80, 0x1), - UNCORE_EVENT_CONSTRAINT(0x83, 0x1), - EVENT_CONSTRAINT_END -}; - -static struct intel_uncore_type snb_uncore_cbox = { - .name = "cbox", - .num_counters = 2, - .num_boxes = 4, - .perf_ctr_bits = 44, - .fixed_ctr_bits = 48, - .perf_ctr = SNB_UNC_CBO_0_PER_CTR0, - .event_ctl = SNB_UNC_CBO_0_PERFEVTSEL0, - .fixed_ctr = SNB_UNC_FIXED_CTR, - .fixed_ctl = SNB_UNC_FIXED_CTR_CTRL, - .single_fixed = 1, - .event_mask = SNB_UNC_RAW_EVENT_MASK, - .msr_offset = SNB_UNC_CBO_MSR_OFFSET, - .constraints = snb_uncore_cbox_constraints, - .ops = &snb_uncore_msr_ops, - .format_group = &snb_uncore_format_group, - .event_descs = snb_uncore_events, -}; - -static struct intel_uncore_type *snb_msr_uncores[] = { - &snb_uncore_cbox, - NULL, -}; - -enum { - SNB_PCI_UNCORE_IMC, -}; - -static struct uncore_event_desc snb_uncore_imc_events[] = { - INTEL_UNCORE_EVENT_DESC(data_reads, "event=0x01"), - INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"), - INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"), - - INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"), - INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"), - INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"), - - { /* end: all zeroes */ }, -}; - -#define SNB_UNCORE_PCI_IMC_EVENT_MASK 0xff -#define SNB_UNCORE_PCI_IMC_BAR_OFFSET 0x48 - -/* page size multiple covering all config regs */ -#define SNB_UNCORE_PCI_IMC_MAP_SIZE 0x6000 - -#define SNB_UNCORE_PCI_IMC_DATA_READS 0x1 -#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE 0x5050 -#define SNB_UNCORE_PCI_IMC_DATA_WRITES 0x2 -#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE 0x5054 -#define SNB_UNCORE_PCI_IMC_CTR_BASE SNB_UNCORE_PCI_IMC_DATA_READS_BASE - -static struct attribute *snb_uncore_imc_formats_attr[] = { - &format_attr_event.attr, - NULL, -}; - -static struct attribute_group snb_uncore_imc_format_group = { - .name = "format", - .attrs = snb_uncore_imc_formats_attr, -}; - -static void snb_uncore_imc_init_box(struct intel_uncore_box *box) -{ - struct pci_dev *pdev = box->pci_dev; - int where = SNB_UNCORE_PCI_IMC_BAR_OFFSET; - resource_size_t addr; - u32 pci_dword; - - pci_read_config_dword(pdev, where, &pci_dword); - addr = pci_dword; - -#ifdef CONFIG_PHYS_ADDR_T_64BIT - pci_read_config_dword(pdev, where + 4, &pci_dword); - addr |= ((resource_size_t)pci_dword << 32); -#endif - - addr &= ~(PAGE_SIZE - 1); - - box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE); - box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL; -} - -static void snb_uncore_imc_enable_box(struct intel_uncore_box *box) -{} - -static void snb_uncore_imc_disable_box(struct intel_uncore_box *box) -{} - -static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{} - -static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event) -{} - -static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - - return (u64)*(unsigned int *)(box->io_addr + hwc->event_base); -} - -/* - * custom event_init() function because we define our own fixed, free - * running counters, so we do not want to conflict with generic uncore - * logic. Also simplifies processing - */ -static int snb_uncore_imc_event_init(struct perf_event *event) -{ - struct intel_uncore_pmu *pmu; - struct intel_uncore_box *box; - struct hw_perf_event *hwc = &event->hw; - u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK; - int idx, base; - - if (event->attr.type != event->pmu->type) - return -ENOENT; - - pmu = uncore_event_to_pmu(event); - /* no device found for this pmu */ - if (pmu->func_id < 0) - return -ENOENT; - - /* Sampling not supported yet */ - if (hwc->sample_period) - return -EINVAL; - - /* unsupported modes and filters */ - if (event->attr.exclude_user || - event->attr.exclude_kernel || - event->attr.exclude_hv || - event->attr.exclude_idle || - event->attr.exclude_host || - event->attr.exclude_guest || - event->attr.sample_period) /* no sampling */ - return -EINVAL; - - /* - * Place all uncore events for a particular physical package - * onto a single cpu - */ - if (event->cpu < 0) - return -EINVAL; - - /* check only supported bits are set */ - if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK) - return -EINVAL; - - box = uncore_pmu_to_box(pmu, event->cpu); - if (!box || box->cpu < 0) - return -EINVAL; - - event->cpu = box->cpu; - - event->hw.idx = -1; - event->hw.last_tag = ~0ULL; - event->hw.extra_reg.idx = EXTRA_REG_NONE; - event->hw.branch_reg.idx = EXTRA_REG_NONE; - /* - * check event is known (whitelist, determines counter) - */ - switch (cfg) { - case SNB_UNCORE_PCI_IMC_DATA_READS: - base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE; - idx = UNCORE_PMC_IDX_FIXED; - break; - case SNB_UNCORE_PCI_IMC_DATA_WRITES: - base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE; - idx = UNCORE_PMC_IDX_FIXED + 1; - break; - default: - return -EINVAL; - } - - /* must be done before validate_group */ - event->hw.event_base = base; - event->hw.config = cfg; - event->hw.idx = idx; - - /* no group validation needed, we have free running counters */ - - return 0; -} - -static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event) -{ - return 0; -} - -static void snb_uncore_imc_event_start(struct perf_event *event, int flags) -{ - struct intel_uncore_box *box = uncore_event_to_box(event); - u64 count; - - if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) - return; - - event->hw.state = 0; - box->n_active++; - - list_add_tail(&event->active_entry, &box->active_list); - - count = snb_uncore_imc_read_counter(box, event); - local64_set(&event->hw.prev_count, count); - - if (box->n_active == 1) - uncore_pmu_start_hrtimer(box); -} - -static void snb_uncore_imc_event_stop(struct perf_event *event, int flags) -{ - struct intel_uncore_box *box = uncore_event_to_box(event); - struct hw_perf_event *hwc = &event->hw; - - if (!(hwc->state & PERF_HES_STOPPED)) { - box->n_active--; - - WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); - hwc->state |= PERF_HES_STOPPED; - - list_del(&event->active_entry); - - if (box->n_active == 0) - uncore_pmu_cancel_hrtimer(box); - } - - if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { - /* - * Drain the remaining delta count out of a event - * that we are disabling: - */ - uncore_perf_event_update(box, event); - hwc->state |= PERF_HES_UPTODATE; - } -} - -static int snb_uncore_imc_event_add(struct perf_event *event, int flags) -{ - struct intel_uncore_box *box = uncore_event_to_box(event); - struct hw_perf_event *hwc = &event->hw; - - if (!box) - return -ENODEV; - - hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; - if (!(flags & PERF_EF_START)) - hwc->state |= PERF_HES_ARCH; - - snb_uncore_imc_event_start(event, 0); - - box->n_events++; - - return 0; -} - -static void snb_uncore_imc_event_del(struct perf_event *event, int flags) -{ - struct intel_uncore_box *box = uncore_event_to_box(event); - int i; - - snb_uncore_imc_event_stop(event, PERF_EF_UPDATE); - - for (i = 0; i < box->n_events; i++) { - if (event == box->event_list[i]) { - --box->n_events; - break; - } - } -} - -static int snb_pci2phy_map_init(int devid) -{ - struct pci_dev *dev = NULL; - int bus; - - dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev); - if (!dev) - return -ENOTTY; - - bus = dev->bus->number; - - uncore_pcibus_to_physid[bus] = 0; - - pci_dev_put(dev); - - return 0; -} - -static struct pmu snb_uncore_imc_pmu = { - .task_ctx_nr = perf_invalid_context, - .event_init = snb_uncore_imc_event_init, - .add = snb_uncore_imc_event_add, - .del = snb_uncore_imc_event_del, - .start = snb_uncore_imc_event_start, - .stop = snb_uncore_imc_event_stop, - .read = uncore_pmu_event_read, -}; - -static struct intel_uncore_ops snb_uncore_imc_ops = { - .init_box = snb_uncore_imc_init_box, - .enable_box = snb_uncore_imc_enable_box, - .disable_box = snb_uncore_imc_disable_box, - .disable_event = snb_uncore_imc_disable_event, - .enable_event = snb_uncore_imc_enable_event, - .hw_config = snb_uncore_imc_hw_config, - .read_counter = snb_uncore_imc_read_counter, -}; - -static struct intel_uncore_type snb_uncore_imc = { - .name = "imc", - .num_counters = 2, - .num_boxes = 1, - .fixed_ctr_bits = 32, - .fixed_ctr = SNB_UNCORE_PCI_IMC_CTR_BASE, - .event_descs = snb_uncore_imc_events, - .format_group = &snb_uncore_imc_format_group, - .perf_ctr = SNB_UNCORE_PCI_IMC_DATA_READS_BASE, - .event_mask = SNB_UNCORE_PCI_IMC_EVENT_MASK, - .ops = &snb_uncore_imc_ops, - .pmu = &snb_uncore_imc_pmu, -}; - -static struct intel_uncore_type *snb_pci_uncores[] = { - [SNB_PCI_UNCORE_IMC] = &snb_uncore_imc, - NULL, -}; - -static DEFINE_PCI_DEVICE_TABLE(snb_uncore_pci_ids) = { - { /* IMC */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC), - .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), - }, - { /* end: all zeroes */ }, -}; - -static DEFINE_PCI_DEVICE_TABLE(ivb_uncore_pci_ids) = { - { /* IMC */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC), - .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), - }, - { /* end: all zeroes */ }, -}; - -static DEFINE_PCI_DEVICE_TABLE(hsw_uncore_pci_ids) = { - { /* IMC */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC), - .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), - }, - { /* end: all zeroes */ }, -}; - -static struct pci_driver snb_uncore_pci_driver = { - .name = "snb_uncore", - .id_table = snb_uncore_pci_ids, -}; - -static struct pci_driver ivb_uncore_pci_driver = { - .name = "ivb_uncore", - .id_table = ivb_uncore_pci_ids, -}; - -static struct pci_driver hsw_uncore_pci_driver = { - .name = "hsw_uncore", - .id_table = hsw_uncore_pci_ids, -}; - -/* end of Sandy Bridge uncore support */ - -/* Nehalem uncore support */ -static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box) -{ - wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0); -} - -static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box) -{ - wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC); -} - -static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - - if (hwc->idx < UNCORE_PMC_IDX_FIXED) - wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN); - else - wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN); -} - -static struct attribute *nhm_uncore_formats_attr[] = { - &format_attr_event.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_inv.attr, - &format_attr_cmask8.attr, - NULL, -}; - -static struct attribute_group nhm_uncore_format_group = { - .name = "format", - .attrs = nhm_uncore_formats_attr, -}; - -static struct uncore_event_desc nhm_uncore_events[] = { - INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"), - INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any, "event=0x2f,umask=0x0f"), - INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any, "event=0x2c,umask=0x0f"), - INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads, "event=0x20,umask=0x01"), - INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes, "event=0x20,umask=0x02"), - INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads, "event=0x20,umask=0x04"), - INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"), - INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads, "event=0x20,umask=0x10"), - INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes, "event=0x20,umask=0x20"), - { /* end: all zeroes */ }, -}; - -static struct intel_uncore_ops nhm_uncore_msr_ops = { - .disable_box = nhm_uncore_msr_disable_box, - .enable_box = nhm_uncore_msr_enable_box, - .disable_event = snb_uncore_msr_disable_event, - .enable_event = nhm_uncore_msr_enable_event, - .read_counter = uncore_msr_read_counter, -}; - -static struct intel_uncore_type nhm_uncore = { - .name = "", - .num_counters = 8, - .num_boxes = 1, - .perf_ctr_bits = 48, - .fixed_ctr_bits = 48, - .event_ctl = NHM_UNC_PERFEVTSEL0, - .perf_ctr = NHM_UNC_UNCORE_PMC0, - .fixed_ctr = NHM_UNC_FIXED_CTR, - .fixed_ctl = NHM_UNC_FIXED_CTR_CTRL, - .event_mask = NHM_UNC_RAW_EVENT_MASK, - .event_descs = nhm_uncore_events, - .ops = &nhm_uncore_msr_ops, - .format_group = &nhm_uncore_format_group, -}; - -static struct intel_uncore_type *nhm_msr_uncores[] = { - &nhm_uncore, - NULL, -}; -/* end of Nehalem uncore support */ - /* Nehalem-EX uncore support */ DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5"); DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7"); @@ -3869,31 +3365,22 @@ static int __init uncore_pci_init(void) uncore_pci_driver = &ivt_uncore_pci_driver; break; case 42: /* Sandy Bridge */ - ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_SNB_IMC); - if (ret) - return ret; - uncore_pci_uncores = snb_pci_uncores; - uncore_pci_driver = &snb_uncore_pci_driver; + ret = snb_uncore_pci_init(); break; case 58: /* Ivy Bridge */ - ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_IVB_IMC); - if (ret) - return ret; - uncore_pci_uncores = snb_pci_uncores; - uncore_pci_driver = &ivb_uncore_pci_driver; + ret = ivb_uncore_pci_init(); break; case 60: /* Haswell */ case 69: /* Haswell Celeron */ - ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_HSW_IMC); - if (ret) - return ret; - uncore_pci_uncores = snb_pci_uncores; - uncore_pci_driver = &hsw_uncore_pci_driver; + ret = hsw_uncore_pci_init(); break; default: return 0; } + if (ret) + return ret; + ret = uncore_types_init(uncore_pci_uncores); if (ret) return ret; @@ -4169,13 +3656,11 @@ static int __init uncore_cpu_init(void) case 30: case 37: /* Westmere */ case 44: - uncore_msr_uncores = nhm_msr_uncores; + nhm_uncore_cpu_init(); break; case 42: /* Sandy Bridge */ case 58: /* Ivy Bridge */ - if (snb_uncore_cbox.num_boxes > max_cores) - snb_uncore_cbox.num_boxes = max_cores; - uncore_msr_uncores = snb_msr_uncores; + snb_uncore_cpu_init(); break; case 45: /* Sandy Bridge-EP */ if (snbep_uncore_cbox.num_boxes > max_cores) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index e5b5fd7554af..86699caaacd8 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -24,55 +24,6 @@ #define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff) -/* SNB event control */ -#define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff -#define SNB_UNC_CTL_UMASK_MASK 0x0000ff00 -#define SNB_UNC_CTL_EDGE_DET (1 << 18) -#define SNB_UNC_CTL_EN (1 << 22) -#define SNB_UNC_CTL_INVERT (1 << 23) -#define SNB_UNC_CTL_CMASK_MASK 0x1f000000 -#define NHM_UNC_CTL_CMASK_MASK 0xff000000 -#define NHM_UNC_FIXED_CTR_CTL_EN (1 << 0) - -#define SNB_UNC_RAW_EVENT_MASK (SNB_UNC_CTL_EV_SEL_MASK | \ - SNB_UNC_CTL_UMASK_MASK | \ - SNB_UNC_CTL_EDGE_DET | \ - SNB_UNC_CTL_INVERT | \ - SNB_UNC_CTL_CMASK_MASK) - -#define NHM_UNC_RAW_EVENT_MASK (SNB_UNC_CTL_EV_SEL_MASK | \ - SNB_UNC_CTL_UMASK_MASK | \ - SNB_UNC_CTL_EDGE_DET | \ - SNB_UNC_CTL_INVERT | \ - NHM_UNC_CTL_CMASK_MASK) - -/* SNB global control register */ -#define SNB_UNC_PERF_GLOBAL_CTL 0x391 -#define SNB_UNC_FIXED_CTR_CTRL 0x394 -#define SNB_UNC_FIXED_CTR 0x395 - -/* SNB uncore global control */ -#define SNB_UNC_GLOBAL_CTL_CORE_ALL ((1 << 4) - 1) -#define SNB_UNC_GLOBAL_CTL_EN (1 << 29) - -/* SNB Cbo register */ -#define SNB_UNC_CBO_0_PERFEVTSEL0 0x700 -#define SNB_UNC_CBO_0_PER_CTR0 0x706 -#define SNB_UNC_CBO_MSR_OFFSET 0x10 - -/* NHM global control register */ -#define NHM_UNC_PERF_GLOBAL_CTL 0x391 -#define NHM_UNC_FIXED_CTR 0x394 -#define NHM_UNC_FIXED_CTR_CTRL 0x395 - -/* NHM uncore global control */ -#define NHM_UNC_GLOBAL_CTL_EN_PC_ALL ((1ULL << 8) - 1) -#define NHM_UNC_GLOBAL_CTL_EN_FC (1ULL << 32) - -/* NHM uncore register */ -#define NHM_UNC_PERFEVTSEL0 0x3c0 -#define NHM_UNC_UNCORE_PMC0 0x3b0 - /* SNB-EP Box level control */ #define SNBEP_PMON_BOX_CTL_RST_CTRL (1 << 0) #define SNBEP_PMON_BOX_CTL_RST_CTRS (1 << 1) @@ -708,3 +659,10 @@ extern struct pci_driver *uncore_pci_driver; extern int uncore_pcibus_to_physid[256]; extern struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX]; extern struct event_constraint uncore_constraint_empty; + +/* perf_event_intel_uncore_snb.c */ +int snb_uncore_pci_init(void); +int ivb_uncore_pci_init(void); +int hsw_uncore_pci_init(void); +void snb_uncore_cpu_init(void); +void nhm_uncore_cpu_init(void); diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c new file mode 100644 index 000000000000..6e7811f3ea73 --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c @@ -0,0 +1,603 @@ +/* Nehalem/SandBridge/Haswell uncore support */ +#include "perf_event_intel_uncore.h" + +/* SNB event control */ +#define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff +#define SNB_UNC_CTL_UMASK_MASK 0x0000ff00 +#define SNB_UNC_CTL_EDGE_DET (1 << 18) +#define SNB_UNC_CTL_EN (1 << 22) +#define SNB_UNC_CTL_INVERT (1 << 23) +#define SNB_UNC_CTL_CMASK_MASK 0x1f000000 +#define NHM_UNC_CTL_CMASK_MASK 0xff000000 +#define NHM_UNC_FIXED_CTR_CTL_EN (1 << 0) + +#define SNB_UNC_RAW_EVENT_MASK (SNB_UNC_CTL_EV_SEL_MASK | \ + SNB_UNC_CTL_UMASK_MASK | \ + SNB_UNC_CTL_EDGE_DET | \ + SNB_UNC_CTL_INVERT | \ + SNB_UNC_CTL_CMASK_MASK) + +#define NHM_UNC_RAW_EVENT_MASK (SNB_UNC_CTL_EV_SEL_MASK | \ + SNB_UNC_CTL_UMASK_MASK | \ + SNB_UNC_CTL_EDGE_DET | \ + SNB_UNC_CTL_INVERT | \ + NHM_UNC_CTL_CMASK_MASK) + +/* SNB global control register */ +#define SNB_UNC_PERF_GLOBAL_CTL 0x391 +#define SNB_UNC_FIXED_CTR_CTRL 0x394 +#define SNB_UNC_FIXED_CTR 0x395 + +/* SNB uncore global control */ +#define SNB_UNC_GLOBAL_CTL_CORE_ALL ((1 << 4) - 1) +#define SNB_UNC_GLOBAL_CTL_EN (1 << 29) + +/* SNB Cbo register */ +#define SNB_UNC_CBO_0_PERFEVTSEL0 0x700 +#define SNB_UNC_CBO_0_PER_CTR0 0x706 +#define SNB_UNC_CBO_MSR_OFFSET 0x10 + +/* NHM global control register */ +#define NHM_UNC_PERF_GLOBAL_CTL 0x391 +#define NHM_UNC_FIXED_CTR 0x394 +#define NHM_UNC_FIXED_CTR_CTRL 0x395 + +/* NHM uncore global control */ +#define NHM_UNC_GLOBAL_CTL_EN_PC_ALL ((1ULL << 8) - 1) +#define NHM_UNC_GLOBAL_CTL_EN_FC (1ULL << 32) + +/* NHM uncore register */ +#define NHM_UNC_PERFEVTSEL0 0x3c0 +#define NHM_UNC_UNCORE_PMC0 0x3b0 + +DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); +DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); +DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); +DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); +DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28"); +DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31"); + +/* Sandy Bridge uncore support */ +static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + if (hwc->idx < UNCORE_PMC_IDX_FIXED) + wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN); + else + wrmsrl(hwc->config_base, SNB_UNC_CTL_EN); +} + +static void snb_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + wrmsrl(event->hw.config_base, 0); +} + +static void snb_uncore_msr_init_box(struct intel_uncore_box *box) +{ + if (box->pmu->pmu_idx == 0) { + wrmsrl(SNB_UNC_PERF_GLOBAL_CTL, + SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL); + } +} + +static struct uncore_event_desc snb_uncore_events[] = { + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"), + { /* end: all zeroes */ }, +}; + +static struct attribute *snb_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_cmask5.attr, + NULL, +}; + +static struct attribute_group snb_uncore_format_group = { + .name = "format", + .attrs = snb_uncore_formats_attr, +}; + +static struct intel_uncore_ops snb_uncore_msr_ops = { + .init_box = snb_uncore_msr_init_box, + .disable_event = snb_uncore_msr_disable_event, + .enable_event = snb_uncore_msr_enable_event, + .read_counter = uncore_msr_read_counter, +}; + +static struct event_constraint snb_uncore_cbox_constraints[] = { + UNCORE_EVENT_CONSTRAINT(0x80, 0x1), + UNCORE_EVENT_CONSTRAINT(0x83, 0x1), + EVENT_CONSTRAINT_END +}; + +static struct intel_uncore_type snb_uncore_cbox = { + .name = "cbox", + .num_counters = 2, + .num_boxes = 4, + .perf_ctr_bits = 44, + .fixed_ctr_bits = 48, + .perf_ctr = SNB_UNC_CBO_0_PER_CTR0, + .event_ctl = SNB_UNC_CBO_0_PERFEVTSEL0, + .fixed_ctr = SNB_UNC_FIXED_CTR, + .fixed_ctl = SNB_UNC_FIXED_CTR_CTRL, + .single_fixed = 1, + .event_mask = SNB_UNC_RAW_EVENT_MASK, + .msr_offset = SNB_UNC_CBO_MSR_OFFSET, + .constraints = snb_uncore_cbox_constraints, + .ops = &snb_uncore_msr_ops, + .format_group = &snb_uncore_format_group, + .event_descs = snb_uncore_events, +}; + +static struct intel_uncore_type *snb_msr_uncores[] = { + &snb_uncore_cbox, + NULL, +}; + +void snb_uncore_cpu_init(void) +{ + uncore_msr_uncores = snb_msr_uncores; + if (snb_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores) + snb_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores; +} + +enum { + SNB_PCI_UNCORE_IMC, +}; + +static struct uncore_event_desc snb_uncore_imc_events[] = { + INTEL_UNCORE_EVENT_DESC(data_reads, "event=0x01"), + INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"), + INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"), + + INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"), + INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"), + INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"), + + { /* end: all zeroes */ }, +}; + +#define SNB_UNCORE_PCI_IMC_EVENT_MASK 0xff +#define SNB_UNCORE_PCI_IMC_BAR_OFFSET 0x48 + +/* page size multiple covering all config regs */ +#define SNB_UNCORE_PCI_IMC_MAP_SIZE 0x6000 + +#define SNB_UNCORE_PCI_IMC_DATA_READS 0x1 +#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE 0x5050 +#define SNB_UNCORE_PCI_IMC_DATA_WRITES 0x2 +#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE 0x5054 +#define SNB_UNCORE_PCI_IMC_CTR_BASE SNB_UNCORE_PCI_IMC_DATA_READS_BASE + +static struct attribute *snb_uncore_imc_formats_attr[] = { + &format_attr_event.attr, + NULL, +}; + +static struct attribute_group snb_uncore_imc_format_group = { + .name = "format", + .attrs = snb_uncore_imc_formats_attr, +}; + +static void snb_uncore_imc_init_box(struct intel_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + int where = SNB_UNCORE_PCI_IMC_BAR_OFFSET; + resource_size_t addr; + u32 pci_dword; + + pci_read_config_dword(pdev, where, &pci_dword); + addr = pci_dword; + +#ifdef CONFIG_PHYS_ADDR_T_64BIT + pci_read_config_dword(pdev, where + 4, &pci_dword); + addr |= ((resource_size_t)pci_dword << 32); +#endif + + addr &= ~(PAGE_SIZE - 1); + + box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE); + box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL; +} + +static void snb_uncore_imc_enable_box(struct intel_uncore_box *box) +{} + +static void snb_uncore_imc_disable_box(struct intel_uncore_box *box) +{} + +static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{} + +static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event) +{} + +static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + return (u64)*(unsigned int *)(box->io_addr + hwc->event_base); +} + +/* + * custom event_init() function because we define our own fixed, free + * running counters, so we do not want to conflict with generic uncore + * logic. Also simplifies processing + */ +static int snb_uncore_imc_event_init(struct perf_event *event) +{ + struct intel_uncore_pmu *pmu; + struct intel_uncore_box *box; + struct hw_perf_event *hwc = &event->hw; + u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK; + int idx, base; + + if (event->attr.type != event->pmu->type) + return -ENOENT; + + pmu = uncore_event_to_pmu(event); + /* no device found for this pmu */ + if (pmu->func_id < 0) + return -ENOENT; + + /* Sampling not supported yet */ + if (hwc->sample_period) + return -EINVAL; + + /* unsupported modes and filters */ + if (event->attr.exclude_user || + event->attr.exclude_kernel || + event->attr.exclude_hv || + event->attr.exclude_idle || + event->attr.exclude_host || + event->attr.exclude_guest || + event->attr.sample_period) /* no sampling */ + return -EINVAL; + + /* + * Place all uncore events for a particular physical package + * onto a single cpu + */ + if (event->cpu < 0) + return -EINVAL; + + /* check only supported bits are set */ + if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK) + return -EINVAL; + + box = uncore_pmu_to_box(pmu, event->cpu); + if (!box || box->cpu < 0) + return -EINVAL; + + event->cpu = box->cpu; + + event->hw.idx = -1; + event->hw.last_tag = ~0ULL; + event->hw.extra_reg.idx = EXTRA_REG_NONE; + event->hw.branch_reg.idx = EXTRA_REG_NONE; + /* + * check event is known (whitelist, determines counter) + */ + switch (cfg) { + case SNB_UNCORE_PCI_IMC_DATA_READS: + base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE; + idx = UNCORE_PMC_IDX_FIXED; + break; + case SNB_UNCORE_PCI_IMC_DATA_WRITES: + base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE; + idx = UNCORE_PMC_IDX_FIXED + 1; + break; + default: + return -EINVAL; + } + + /* must be done before validate_group */ + event->hw.event_base = base; + event->hw.config = cfg; + event->hw.idx = idx; + + /* no group validation needed, we have free running counters */ + + return 0; +} + +static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event) +{ + return 0; +} + +static void snb_uncore_imc_event_start(struct perf_event *event, int flags) +{ + struct intel_uncore_box *box = uncore_event_to_box(event); + u64 count; + + if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) + return; + + event->hw.state = 0; + box->n_active++; + + list_add_tail(&event->active_entry, &box->active_list); + + count = snb_uncore_imc_read_counter(box, event); + local64_set(&event->hw.prev_count, count); + + if (box->n_active == 1) + uncore_pmu_start_hrtimer(box); +} + +static void snb_uncore_imc_event_stop(struct perf_event *event, int flags) +{ + struct intel_uncore_box *box = uncore_event_to_box(event); + struct hw_perf_event *hwc = &event->hw; + + if (!(hwc->state & PERF_HES_STOPPED)) { + box->n_active--; + + WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); + hwc->state |= PERF_HES_STOPPED; + + list_del(&event->active_entry); + + if (box->n_active == 0) + uncore_pmu_cancel_hrtimer(box); + } + + if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { + /* + * Drain the remaining delta count out of a event + * that we are disabling: + */ + uncore_perf_event_update(box, event); + hwc->state |= PERF_HES_UPTODATE; + } +} + +static int snb_uncore_imc_event_add(struct perf_event *event, int flags) +{ + struct intel_uncore_box *box = uncore_event_to_box(event); + struct hw_perf_event *hwc = &event->hw; + + if (!box) + return -ENODEV; + + hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; + if (!(flags & PERF_EF_START)) + hwc->state |= PERF_HES_ARCH; + + snb_uncore_imc_event_start(event, 0); + + box->n_events++; + + return 0; +} + +static void snb_uncore_imc_event_del(struct perf_event *event, int flags) +{ + struct intel_uncore_box *box = uncore_event_to_box(event); + int i; + + snb_uncore_imc_event_stop(event, PERF_EF_UPDATE); + + for (i = 0; i < box->n_events; i++) { + if (event == box->event_list[i]) { + --box->n_events; + break; + } + } +} + +static int snb_pci2phy_map_init(int devid) +{ + struct pci_dev *dev = NULL; + int bus; + + dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev); + if (!dev) + return -ENOTTY; + + bus = dev->bus->number; + + uncore_pcibus_to_physid[bus] = 0; + + pci_dev_put(dev); + + return 0; +} + +static struct pmu snb_uncore_imc_pmu = { + .task_ctx_nr = perf_invalid_context, + .event_init = snb_uncore_imc_event_init, + .add = snb_uncore_imc_event_add, + .del = snb_uncore_imc_event_del, + .start = snb_uncore_imc_event_start, + .stop = snb_uncore_imc_event_stop, + .read = uncore_pmu_event_read, +}; + +static struct intel_uncore_ops snb_uncore_imc_ops = { + .init_box = snb_uncore_imc_init_box, + .enable_box = snb_uncore_imc_enable_box, + .disable_box = snb_uncore_imc_disable_box, + .disable_event = snb_uncore_imc_disable_event, + .enable_event = snb_uncore_imc_enable_event, + .hw_config = snb_uncore_imc_hw_config, + .read_counter = snb_uncore_imc_read_counter, +}; + +static struct intel_uncore_type snb_uncore_imc = { + .name = "imc", + .num_counters = 2, + .num_boxes = 1, + .fixed_ctr_bits = 32, + .fixed_ctr = SNB_UNCORE_PCI_IMC_CTR_BASE, + .event_descs = snb_uncore_imc_events, + .format_group = &snb_uncore_imc_format_group, + .perf_ctr = SNB_UNCORE_PCI_IMC_DATA_READS_BASE, + .event_mask = SNB_UNCORE_PCI_IMC_EVENT_MASK, + .ops = &snb_uncore_imc_ops, + .pmu = &snb_uncore_imc_pmu, +}; + +static struct intel_uncore_type *snb_pci_uncores[] = { + [SNB_PCI_UNCORE_IMC] = &snb_uncore_imc, + NULL, +}; + +static DEFINE_PCI_DEVICE_TABLE(snb_uncore_pci_ids) = { + { /* IMC */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC), + .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), + }, + { /* end: all zeroes */ }, +}; + +static DEFINE_PCI_DEVICE_TABLE(ivb_uncore_pci_ids) = { + { /* IMC */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC), + .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), + }, + { /* end: all zeroes */ }, +}; + +static DEFINE_PCI_DEVICE_TABLE(hsw_uncore_pci_ids) = { + { /* IMC */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC), + .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), + }, + { /* end: all zeroes */ }, +}; + +static struct pci_driver snb_uncore_pci_driver = { + .name = "snb_uncore", + .id_table = snb_uncore_pci_ids, +}; + +static struct pci_driver ivb_uncore_pci_driver = { + .name = "ivb_uncore", + .id_table = ivb_uncore_pci_ids, +}; + +static struct pci_driver hsw_uncore_pci_driver = { + .name = "hsw_uncore", + .id_table = hsw_uncore_pci_ids, +}; + +int snb_uncore_pci_init(void) +{ + int ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_SNB_IMC); + if (ret) + return ret; + uncore_pci_uncores = snb_pci_uncores; + uncore_pci_driver = &snb_uncore_pci_driver; + return 0; +} + +int ivb_uncore_pci_init(void) +{ + int ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_IVB_IMC); + if (ret) + return ret; + uncore_pci_uncores = snb_pci_uncores; + uncore_pci_driver = &ivb_uncore_pci_driver; + return 0; +} + +int hsw_uncore_pci_init(void) +{ + int ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_HSW_IMC); + if (ret) + return ret; + uncore_pci_uncores = snb_pci_uncores; + uncore_pci_driver = &hsw_uncore_pci_driver; + return 0; +} + +/* end of Sandy Bridge uncore support */ + +/* Nehalem uncore support */ +static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box) +{ + wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0); +} + +static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box) +{ + wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC); +} + +static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + if (hwc->idx < UNCORE_PMC_IDX_FIXED) + wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN); + else + wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN); +} + +static struct attribute *nhm_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_cmask8.attr, + NULL, +}; + +static struct attribute_group nhm_uncore_format_group = { + .name = "format", + .attrs = nhm_uncore_formats_attr, +}; + +static struct uncore_event_desc nhm_uncore_events[] = { + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"), + INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any, "event=0x2f,umask=0x0f"), + INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any, "event=0x2c,umask=0x0f"), + INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads, "event=0x20,umask=0x01"), + INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes, "event=0x20,umask=0x02"), + INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads, "event=0x20,umask=0x04"), + INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"), + INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads, "event=0x20,umask=0x10"), + INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes, "event=0x20,umask=0x20"), + { /* end: all zeroes */ }, +}; + +static struct intel_uncore_ops nhm_uncore_msr_ops = { + .disable_box = nhm_uncore_msr_disable_box, + .enable_box = nhm_uncore_msr_enable_box, + .disable_event = snb_uncore_msr_disable_event, + .enable_event = nhm_uncore_msr_enable_event, + .read_counter = uncore_msr_read_counter, +}; + +static struct intel_uncore_type nhm_uncore = { + .name = "", + .num_counters = 8, + .num_boxes = 1, + .perf_ctr_bits = 48, + .fixed_ctr_bits = 48, + .event_ctl = NHM_UNC_PERFEVTSEL0, + .perf_ctr = NHM_UNC_UNCORE_PMC0, + .fixed_ctr = NHM_UNC_FIXED_CTR, + .fixed_ctl = NHM_UNC_FIXED_CTR_CTRL, + .event_mask = NHM_UNC_RAW_EVENT_MASK, + .event_descs = nhm_uncore_events, + .ops = &nhm_uncore_msr_ops, + .format_group = &nhm_uncore_format_group, +}; + +static struct intel_uncore_type *nhm_msr_uncores[] = { + &nhm_uncore, + NULL, +}; + +void nhm_uncore_cpu_init(void) +{ + uncore_msr_uncores = nhm_msr_uncores; +} + +/* end of Nehalem uncore support */ -- GitLab From 8268fdfc45b747bcb3351464efefbdf611aeea9b Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 30 Jul 2014 15:22:14 +0800 Subject: [PATCH 0197/5088] perf/x86/uncore: Move SNB/IVB-EP specific code to seperate file Signed-off-by: Yan, Zheng Signed-off-by: Peter Zijlstra Cc: Andi Kleen Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Paul Mackerras Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406704935-27708-3-git-send-email-zheng.z.yan@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/Makefile | 1 + arch/x86/kernel/cpu/perf_event_intel_uncore.c | 1465 +-------------- arch/x86/kernel/cpu/perf_event_intel_uncore.h | 164 +- .../cpu/perf_event_intel_uncore_snbep.c | 1644 +++++++++++++++++ 4 files changed, 1655 insertions(+), 1619 deletions(-) create mode 100644 arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 5ca8f4a39106..7dee8664573a 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -37,6 +37,7 @@ endif obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o perf_event_intel_uncore_snb.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore_snbep.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_rapl.o endif diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index feb085c8ca4e..cf6966a37580 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -32,46 +32,10 @@ ssize_t uncore_event_show(struct kobject *kobj, ((1ULL << (n)) - 1))) DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); -DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21"); DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); -DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19"); DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31"); -DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28"); -DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15"); -DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30"); -DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51"); -DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4"); -DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8"); -DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17"); -DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47"); -DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22"); -DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22"); -DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31"); -DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60"); -DEFINE_UNCORE_FORMAT_ATTR(filter_band0, filter_band0, "config1:0-7"); -DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15"); -DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23"); -DEFINE_UNCORE_FORMAT_ATTR(filter_band3, filter_band3, "config1:24-31"); -DEFINE_UNCORE_FORMAT_ATTR(match_rds, match_rds, "config1:48-51"); -DEFINE_UNCORE_FORMAT_ATTR(match_rnid30, match_rnid30, "config1:32-35"); -DEFINE_UNCORE_FORMAT_ATTR(match_rnid4, match_rnid4, "config1:31"); -DEFINE_UNCORE_FORMAT_ATTR(match_dnid, match_dnid, "config1:13-17"); -DEFINE_UNCORE_FORMAT_ATTR(match_mc, match_mc, "config1:9-12"); -DEFINE_UNCORE_FORMAT_ATTR(match_opc, match_opc, "config1:5-8"); -DEFINE_UNCORE_FORMAT_ATTR(match_vnw, match_vnw, "config1:3-4"); -DEFINE_UNCORE_FORMAT_ATTR(match0, match0, "config1:0-31"); -DEFINE_UNCORE_FORMAT_ATTR(match1, match1, "config1:32-63"); -DEFINE_UNCORE_FORMAT_ATTR(mask_rds, mask_rds, "config2:48-51"); -DEFINE_UNCORE_FORMAT_ATTR(mask_rnid30, mask_rnid30, "config2:32-35"); -DEFINE_UNCORE_FORMAT_ATTR(mask_rnid4, mask_rnid4, "config2:31"); -DEFINE_UNCORE_FORMAT_ATTR(mask_dnid, mask_dnid, "config2:13-17"); -DEFINE_UNCORE_FORMAT_ATTR(mask_mc, mask_mc, "config2:9-12"); -DEFINE_UNCORE_FORMAT_ATTR(mask_opc, mask_opc, "config2:5-8"); -DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4"); -DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31"); -DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63"); struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event) { @@ -194,1415 +158,6 @@ u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx) return config; } -/* Sandy Bridge-EP uncore support */ -static struct intel_uncore_type snbep_uncore_cbox; -static struct intel_uncore_type snbep_uncore_pcu; - -static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box) -{ - struct pci_dev *pdev = box->pci_dev; - int box_ctl = uncore_pci_box_ctl(box); - u32 config = 0; - - if (!pci_read_config_dword(pdev, box_ctl, &config)) { - config |= SNBEP_PMON_BOX_CTL_FRZ; - pci_write_config_dword(pdev, box_ctl, config); - } -} - -static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box) -{ - struct pci_dev *pdev = box->pci_dev; - int box_ctl = uncore_pci_box_ctl(box); - u32 config = 0; - - if (!pci_read_config_dword(pdev, box_ctl, &config)) { - config &= ~SNBEP_PMON_BOX_CTL_FRZ; - pci_write_config_dword(pdev, box_ctl, config); - } -} - -static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct pci_dev *pdev = box->pci_dev; - struct hw_perf_event *hwc = &event->hw; - - pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); -} - -static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct pci_dev *pdev = box->pci_dev; - struct hw_perf_event *hwc = &event->hw; - - pci_write_config_dword(pdev, hwc->config_base, hwc->config); -} - -static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, struct perf_event *event) -{ - struct pci_dev *pdev = box->pci_dev; - struct hw_perf_event *hwc = &event->hw; - u64 count = 0; - - pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count); - pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1); - - return count; -} - -static void snbep_uncore_pci_init_box(struct intel_uncore_box *box) -{ - struct pci_dev *pdev = box->pci_dev; - - pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, SNBEP_PMON_BOX_CTL_INT); -} - -static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box) -{ - u64 config; - unsigned msr; - - msr = uncore_msr_box_ctl(box); - if (msr) { - rdmsrl(msr, config); - config |= SNBEP_PMON_BOX_CTL_FRZ; - wrmsrl(msr, config); - } -} - -static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box) -{ - u64 config; - unsigned msr; - - msr = uncore_msr_box_ctl(box); - if (msr) { - rdmsrl(msr, config); - config &= ~SNBEP_PMON_BOX_CTL_FRZ; - wrmsrl(msr, config); - } -} - -static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - - if (reg1->idx != EXTRA_REG_NONE) - wrmsrl(reg1->reg, uncore_shared_reg_config(box, 0)); - - wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); -} - -static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box, - struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - - wrmsrl(hwc->config_base, hwc->config); -} - -static void snbep_uncore_msr_init_box(struct intel_uncore_box *box) -{ - unsigned msr = uncore_msr_box_ctl(box); - - if (msr) - wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT); -} - -static struct attribute *snbep_uncore_formats_attr[] = { - &format_attr_event.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_inv.attr, - &format_attr_thresh8.attr, - NULL, -}; - -static struct attribute *snbep_uncore_ubox_formats_attr[] = { - &format_attr_event.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_inv.attr, - &format_attr_thresh5.attr, - NULL, -}; - -static struct attribute *snbep_uncore_cbox_formats_attr[] = { - &format_attr_event.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_tid_en.attr, - &format_attr_inv.attr, - &format_attr_thresh8.attr, - &format_attr_filter_tid.attr, - &format_attr_filter_nid.attr, - &format_attr_filter_state.attr, - &format_attr_filter_opc.attr, - NULL, -}; - -static struct attribute *snbep_uncore_pcu_formats_attr[] = { - &format_attr_event_ext.attr, - &format_attr_occ_sel.attr, - &format_attr_edge.attr, - &format_attr_inv.attr, - &format_attr_thresh5.attr, - &format_attr_occ_invert.attr, - &format_attr_occ_edge.attr, - &format_attr_filter_band0.attr, - &format_attr_filter_band1.attr, - &format_attr_filter_band2.attr, - &format_attr_filter_band3.attr, - NULL, -}; - -static struct attribute *snbep_uncore_qpi_formats_attr[] = { - &format_attr_event_ext.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_inv.attr, - &format_attr_thresh8.attr, - &format_attr_match_rds.attr, - &format_attr_match_rnid30.attr, - &format_attr_match_rnid4.attr, - &format_attr_match_dnid.attr, - &format_attr_match_mc.attr, - &format_attr_match_opc.attr, - &format_attr_match_vnw.attr, - &format_attr_match0.attr, - &format_attr_match1.attr, - &format_attr_mask_rds.attr, - &format_attr_mask_rnid30.attr, - &format_attr_mask_rnid4.attr, - &format_attr_mask_dnid.attr, - &format_attr_mask_mc.attr, - &format_attr_mask_opc.attr, - &format_attr_mask_vnw.attr, - &format_attr_mask0.attr, - &format_attr_mask1.attr, - NULL, -}; - -static struct uncore_event_desc snbep_uncore_imc_events[] = { - INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"), - INTEL_UNCORE_EVENT_DESC(cas_count_read, "event=0x04,umask=0x03"), - INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"), - { /* end: all zeroes */ }, -}; - -static struct uncore_event_desc snbep_uncore_qpi_events[] = { - INTEL_UNCORE_EVENT_DESC(clockticks, "event=0x14"), - INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"), - INTEL_UNCORE_EVENT_DESC(drs_data, "event=0x102,umask=0x08"), - INTEL_UNCORE_EVENT_DESC(ncb_data, "event=0x103,umask=0x04"), - { /* end: all zeroes */ }, -}; - -static struct attribute_group snbep_uncore_format_group = { - .name = "format", - .attrs = snbep_uncore_formats_attr, -}; - -static struct attribute_group snbep_uncore_ubox_format_group = { - .name = "format", - .attrs = snbep_uncore_ubox_formats_attr, -}; - -static struct attribute_group snbep_uncore_cbox_format_group = { - .name = "format", - .attrs = snbep_uncore_cbox_formats_attr, -}; - -static struct attribute_group snbep_uncore_pcu_format_group = { - .name = "format", - .attrs = snbep_uncore_pcu_formats_attr, -}; - -static struct attribute_group snbep_uncore_qpi_format_group = { - .name = "format", - .attrs = snbep_uncore_qpi_formats_attr, -}; - -#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \ - .init_box = snbep_uncore_msr_init_box, \ - .disable_box = snbep_uncore_msr_disable_box, \ - .enable_box = snbep_uncore_msr_enable_box, \ - .disable_event = snbep_uncore_msr_disable_event, \ - .enable_event = snbep_uncore_msr_enable_event, \ - .read_counter = uncore_msr_read_counter - -static struct intel_uncore_ops snbep_uncore_msr_ops = { - SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), -}; - -#define SNBEP_UNCORE_PCI_OPS_COMMON_INIT() \ - .init_box = snbep_uncore_pci_init_box, \ - .disable_box = snbep_uncore_pci_disable_box, \ - .enable_box = snbep_uncore_pci_enable_box, \ - .disable_event = snbep_uncore_pci_disable_event, \ - .read_counter = snbep_uncore_pci_read_counter - -static struct intel_uncore_ops snbep_uncore_pci_ops = { - SNBEP_UNCORE_PCI_OPS_COMMON_INIT(), - .enable_event = snbep_uncore_pci_enable_event, \ -}; - -static struct event_constraint snbep_uncore_cbox_constraints[] = { - UNCORE_EVENT_CONSTRAINT(0x01, 0x1), - UNCORE_EVENT_CONSTRAINT(0x02, 0x3), - UNCORE_EVENT_CONSTRAINT(0x04, 0x3), - UNCORE_EVENT_CONSTRAINT(0x05, 0x3), - UNCORE_EVENT_CONSTRAINT(0x07, 0x3), - UNCORE_EVENT_CONSTRAINT(0x09, 0x3), - UNCORE_EVENT_CONSTRAINT(0x11, 0x1), - UNCORE_EVENT_CONSTRAINT(0x12, 0x3), - UNCORE_EVENT_CONSTRAINT(0x13, 0x3), - UNCORE_EVENT_CONSTRAINT(0x1b, 0xc), - UNCORE_EVENT_CONSTRAINT(0x1c, 0xc), - UNCORE_EVENT_CONSTRAINT(0x1d, 0xc), - UNCORE_EVENT_CONSTRAINT(0x1e, 0xc), - EVENT_CONSTRAINT_OVERLAP(0x1f, 0xe, 0xff), - UNCORE_EVENT_CONSTRAINT(0x21, 0x3), - UNCORE_EVENT_CONSTRAINT(0x23, 0x3), - UNCORE_EVENT_CONSTRAINT(0x31, 0x3), - UNCORE_EVENT_CONSTRAINT(0x32, 0x3), - UNCORE_EVENT_CONSTRAINT(0x33, 0x3), - UNCORE_EVENT_CONSTRAINT(0x34, 0x3), - UNCORE_EVENT_CONSTRAINT(0x35, 0x3), - UNCORE_EVENT_CONSTRAINT(0x36, 0x1), - UNCORE_EVENT_CONSTRAINT(0x37, 0x3), - UNCORE_EVENT_CONSTRAINT(0x38, 0x3), - UNCORE_EVENT_CONSTRAINT(0x39, 0x3), - UNCORE_EVENT_CONSTRAINT(0x3b, 0x1), - EVENT_CONSTRAINT_END -}; - -static struct event_constraint snbep_uncore_r2pcie_constraints[] = { - UNCORE_EVENT_CONSTRAINT(0x10, 0x3), - UNCORE_EVENT_CONSTRAINT(0x11, 0x3), - UNCORE_EVENT_CONSTRAINT(0x12, 0x1), - UNCORE_EVENT_CONSTRAINT(0x23, 0x3), - UNCORE_EVENT_CONSTRAINT(0x24, 0x3), - UNCORE_EVENT_CONSTRAINT(0x25, 0x3), - UNCORE_EVENT_CONSTRAINT(0x26, 0x3), - UNCORE_EVENT_CONSTRAINT(0x32, 0x3), - UNCORE_EVENT_CONSTRAINT(0x33, 0x3), - UNCORE_EVENT_CONSTRAINT(0x34, 0x3), - EVENT_CONSTRAINT_END -}; - -static struct event_constraint snbep_uncore_r3qpi_constraints[] = { - UNCORE_EVENT_CONSTRAINT(0x10, 0x3), - UNCORE_EVENT_CONSTRAINT(0x11, 0x3), - UNCORE_EVENT_CONSTRAINT(0x12, 0x3), - UNCORE_EVENT_CONSTRAINT(0x13, 0x1), - UNCORE_EVENT_CONSTRAINT(0x20, 0x3), - UNCORE_EVENT_CONSTRAINT(0x21, 0x3), - UNCORE_EVENT_CONSTRAINT(0x22, 0x3), - UNCORE_EVENT_CONSTRAINT(0x23, 0x3), - UNCORE_EVENT_CONSTRAINT(0x24, 0x3), - UNCORE_EVENT_CONSTRAINT(0x25, 0x3), - UNCORE_EVENT_CONSTRAINT(0x26, 0x3), - UNCORE_EVENT_CONSTRAINT(0x28, 0x3), - UNCORE_EVENT_CONSTRAINT(0x29, 0x3), - UNCORE_EVENT_CONSTRAINT(0x2a, 0x3), - UNCORE_EVENT_CONSTRAINT(0x2b, 0x3), - UNCORE_EVENT_CONSTRAINT(0x2c, 0x3), - UNCORE_EVENT_CONSTRAINT(0x2d, 0x3), - UNCORE_EVENT_CONSTRAINT(0x2e, 0x3), - UNCORE_EVENT_CONSTRAINT(0x2f, 0x3), - UNCORE_EVENT_CONSTRAINT(0x30, 0x3), - UNCORE_EVENT_CONSTRAINT(0x31, 0x3), - UNCORE_EVENT_CONSTRAINT(0x32, 0x3), - UNCORE_EVENT_CONSTRAINT(0x33, 0x3), - UNCORE_EVENT_CONSTRAINT(0x34, 0x3), - UNCORE_EVENT_CONSTRAINT(0x36, 0x3), - UNCORE_EVENT_CONSTRAINT(0x37, 0x3), - UNCORE_EVENT_CONSTRAINT(0x38, 0x3), - UNCORE_EVENT_CONSTRAINT(0x39, 0x3), - EVENT_CONSTRAINT_END -}; - -static struct intel_uncore_type snbep_uncore_ubox = { - .name = "ubox", - .num_counters = 2, - .num_boxes = 1, - .perf_ctr_bits = 44, - .fixed_ctr_bits = 48, - .perf_ctr = SNBEP_U_MSR_PMON_CTR0, - .event_ctl = SNBEP_U_MSR_PMON_CTL0, - .event_mask = SNBEP_U_MSR_PMON_RAW_EVENT_MASK, - .fixed_ctr = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR, - .fixed_ctl = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL, - .ops = &snbep_uncore_msr_ops, - .format_group = &snbep_uncore_ubox_format_group, -}; - -static struct extra_reg snbep_uncore_cbox_extra_regs[] = { - SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN, - SNBEP_CBO_PMON_CTL_TID_EN, 0x1), - SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4), - SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6), - SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4), - SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6), - SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4), - SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6), - SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6), - SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0xa), - SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0xa), - SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x2), - SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x2), - SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x2), - SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x2), - SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0xa), - SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0xa), - SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x2), - SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x2), - SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x2), - SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x2), - EVENT_EXTRA_END -}; - -static void snbep_cbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - struct intel_uncore_extra_reg *er = &box->shared_regs[0]; - int i; - - if (uncore_box_is_fake(box)) - return; - - for (i = 0; i < 5; i++) { - if (reg1->alloc & (0x1 << i)) - atomic_sub(1 << (i * 6), &er->ref); - } - reg1->alloc = 0; -} - -static struct event_constraint * -__snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event, - u64 (*cbox_filter_mask)(int fields)) -{ - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - struct intel_uncore_extra_reg *er = &box->shared_regs[0]; - int i, alloc = 0; - unsigned long flags; - u64 mask; - - if (reg1->idx == EXTRA_REG_NONE) - return NULL; - - raw_spin_lock_irqsave(&er->lock, flags); - for (i = 0; i < 5; i++) { - if (!(reg1->idx & (0x1 << i))) - continue; - if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i))) - continue; - - mask = cbox_filter_mask(0x1 << i); - if (!__BITS_VALUE(atomic_read(&er->ref), i, 6) || - !((reg1->config ^ er->config) & mask)) { - atomic_add(1 << (i * 6), &er->ref); - er->config &= ~mask; - er->config |= reg1->config & mask; - alloc |= (0x1 << i); - } else { - break; - } - } - raw_spin_unlock_irqrestore(&er->lock, flags); - if (i < 5) - goto fail; - - if (!uncore_box_is_fake(box)) - reg1->alloc |= alloc; - - return NULL; -fail: - for (; i >= 0; i--) { - if (alloc & (0x1 << i)) - atomic_sub(1 << (i * 6), &er->ref); - } - return &uncore_constraint_empty; -} - -static u64 snbep_cbox_filter_mask(int fields) -{ - u64 mask = 0; - - if (fields & 0x1) - mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_TID; - if (fields & 0x2) - mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_NID; - if (fields & 0x4) - mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE; - if (fields & 0x8) - mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC; - - return mask; -} - -static struct event_constraint * -snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) -{ - return __snbep_cbox_get_constraint(box, event, snbep_cbox_filter_mask); -} - -static int snbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - struct extra_reg *er; - int idx = 0; - - for (er = snbep_uncore_cbox_extra_regs; er->msr; er++) { - if (er->event != (event->hw.config & er->config_mask)) - continue; - idx |= er->idx; - } - - if (idx) { - reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER + - SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx; - reg1->config = event->attr.config1 & snbep_cbox_filter_mask(idx); - reg1->idx = idx; - } - return 0; -} - -static struct intel_uncore_ops snbep_uncore_cbox_ops = { - SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), - .hw_config = snbep_cbox_hw_config, - .get_constraint = snbep_cbox_get_constraint, - .put_constraint = snbep_cbox_put_constraint, -}; - -static struct intel_uncore_type snbep_uncore_cbox = { - .name = "cbox", - .num_counters = 4, - .num_boxes = 8, - .perf_ctr_bits = 44, - .event_ctl = SNBEP_C0_MSR_PMON_CTL0, - .perf_ctr = SNBEP_C0_MSR_PMON_CTR0, - .event_mask = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK, - .box_ctl = SNBEP_C0_MSR_PMON_BOX_CTL, - .msr_offset = SNBEP_CBO_MSR_OFFSET, - .num_shared_regs = 1, - .constraints = snbep_uncore_cbox_constraints, - .ops = &snbep_uncore_cbox_ops, - .format_group = &snbep_uncore_cbox_format_group, -}; - -static u64 snbep_pcu_alter_er(struct perf_event *event, int new_idx, bool modify) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - u64 config = reg1->config; - - if (new_idx > reg1->idx) - config <<= 8 * (new_idx - reg1->idx); - else - config >>= 8 * (reg1->idx - new_idx); - - if (modify) { - hwc->config += new_idx - reg1->idx; - reg1->config = config; - reg1->idx = new_idx; - } - return config; -} - -static struct event_constraint * -snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - struct intel_uncore_extra_reg *er = &box->shared_regs[0]; - unsigned long flags; - int idx = reg1->idx; - u64 mask, config1 = reg1->config; - bool ok = false; - - if (reg1->idx == EXTRA_REG_NONE || - (!uncore_box_is_fake(box) && reg1->alloc)) - return NULL; -again: - mask = 0xffULL << (idx * 8); - raw_spin_lock_irqsave(&er->lock, flags); - if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) || - !((config1 ^ er->config) & mask)) { - atomic_add(1 << (idx * 8), &er->ref); - er->config &= ~mask; - er->config |= config1 & mask; - ok = true; - } - raw_spin_unlock_irqrestore(&er->lock, flags); - - if (!ok) { - idx = (idx + 1) % 4; - if (idx != reg1->idx) { - config1 = snbep_pcu_alter_er(event, idx, false); - goto again; - } - return &uncore_constraint_empty; - } - - if (!uncore_box_is_fake(box)) { - if (idx != reg1->idx) - snbep_pcu_alter_er(event, idx, true); - reg1->alloc = 1; - } - return NULL; -} - -static void snbep_pcu_put_constraint(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - struct intel_uncore_extra_reg *er = &box->shared_regs[0]; - - if (uncore_box_is_fake(box) || !reg1->alloc) - return; - - atomic_sub(1 << (reg1->idx * 8), &er->ref); - reg1->alloc = 0; -} - -static int snbep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK; - - if (ev_sel >= 0xb && ev_sel <= 0xe) { - reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER; - reg1->idx = ev_sel - 0xb; - reg1->config = event->attr.config1 & (0xff << reg1->idx); - } - return 0; -} - -static struct intel_uncore_ops snbep_uncore_pcu_ops = { - SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), - .hw_config = snbep_pcu_hw_config, - .get_constraint = snbep_pcu_get_constraint, - .put_constraint = snbep_pcu_put_constraint, -}; - -static struct intel_uncore_type snbep_uncore_pcu = { - .name = "pcu", - .num_counters = 4, - .num_boxes = 1, - .perf_ctr_bits = 48, - .perf_ctr = SNBEP_PCU_MSR_PMON_CTR0, - .event_ctl = SNBEP_PCU_MSR_PMON_CTL0, - .event_mask = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK, - .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL, - .num_shared_regs = 1, - .ops = &snbep_uncore_pcu_ops, - .format_group = &snbep_uncore_pcu_format_group, -}; - -static struct intel_uncore_type *snbep_msr_uncores[] = { - &snbep_uncore_ubox, - &snbep_uncore_cbox, - &snbep_uncore_pcu, - NULL, -}; - -enum { - SNBEP_PCI_QPI_PORT0_FILTER, - SNBEP_PCI_QPI_PORT1_FILTER, -}; - -static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - struct hw_perf_event_extra *reg2 = &hwc->branch_reg; - - if ((hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK) == 0x38) { - reg1->idx = 0; - reg1->reg = SNBEP_Q_Py_PCI_PMON_PKT_MATCH0; - reg1->config = event->attr.config1; - reg2->reg = SNBEP_Q_Py_PCI_PMON_PKT_MASK0; - reg2->config = event->attr.config2; - } - return 0; -} - -static void snbep_qpi_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct pci_dev *pdev = box->pci_dev; - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - struct hw_perf_event_extra *reg2 = &hwc->branch_reg; - - if (reg1->idx != EXTRA_REG_NONE) { - int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER; - struct pci_dev *filter_pdev = uncore_extra_pci_dev[box->phys_id][idx]; - WARN_ON_ONCE(!filter_pdev); - if (filter_pdev) { - pci_write_config_dword(filter_pdev, reg1->reg, - (u32)reg1->config); - pci_write_config_dword(filter_pdev, reg1->reg + 4, - (u32)(reg1->config >> 32)); - pci_write_config_dword(filter_pdev, reg2->reg, - (u32)reg2->config); - pci_write_config_dword(filter_pdev, reg2->reg + 4, - (u32)(reg2->config >> 32)); - } - } - - pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); -} - -static struct intel_uncore_ops snbep_uncore_qpi_ops = { - SNBEP_UNCORE_PCI_OPS_COMMON_INIT(), - .enable_event = snbep_qpi_enable_event, - .hw_config = snbep_qpi_hw_config, - .get_constraint = uncore_get_constraint, - .put_constraint = uncore_put_constraint, -}; - -#define SNBEP_UNCORE_PCI_COMMON_INIT() \ - .perf_ctr = SNBEP_PCI_PMON_CTR0, \ - .event_ctl = SNBEP_PCI_PMON_CTL0, \ - .event_mask = SNBEP_PMON_RAW_EVENT_MASK, \ - .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ - .ops = &snbep_uncore_pci_ops, \ - .format_group = &snbep_uncore_format_group - -static struct intel_uncore_type snbep_uncore_ha = { - .name = "ha", - .num_counters = 4, - .num_boxes = 1, - .perf_ctr_bits = 48, - SNBEP_UNCORE_PCI_COMMON_INIT(), -}; - -static struct intel_uncore_type snbep_uncore_imc = { - .name = "imc", - .num_counters = 4, - .num_boxes = 4, - .perf_ctr_bits = 48, - .fixed_ctr_bits = 48, - .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, - .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, - .event_descs = snbep_uncore_imc_events, - SNBEP_UNCORE_PCI_COMMON_INIT(), -}; - -static struct intel_uncore_type snbep_uncore_qpi = { - .name = "qpi", - .num_counters = 4, - .num_boxes = 2, - .perf_ctr_bits = 48, - .perf_ctr = SNBEP_PCI_PMON_CTR0, - .event_ctl = SNBEP_PCI_PMON_CTL0, - .event_mask = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK, - .box_ctl = SNBEP_PCI_PMON_BOX_CTL, - .num_shared_regs = 1, - .ops = &snbep_uncore_qpi_ops, - .event_descs = snbep_uncore_qpi_events, - .format_group = &snbep_uncore_qpi_format_group, -}; - - -static struct intel_uncore_type snbep_uncore_r2pcie = { - .name = "r2pcie", - .num_counters = 4, - .num_boxes = 1, - .perf_ctr_bits = 44, - .constraints = snbep_uncore_r2pcie_constraints, - SNBEP_UNCORE_PCI_COMMON_INIT(), -}; - -static struct intel_uncore_type snbep_uncore_r3qpi = { - .name = "r3qpi", - .num_counters = 3, - .num_boxes = 2, - .perf_ctr_bits = 44, - .constraints = snbep_uncore_r3qpi_constraints, - SNBEP_UNCORE_PCI_COMMON_INIT(), -}; - -enum { - SNBEP_PCI_UNCORE_HA, - SNBEP_PCI_UNCORE_IMC, - SNBEP_PCI_UNCORE_QPI, - SNBEP_PCI_UNCORE_R2PCIE, - SNBEP_PCI_UNCORE_R3QPI, -}; - -static struct intel_uncore_type *snbep_pci_uncores[] = { - [SNBEP_PCI_UNCORE_HA] = &snbep_uncore_ha, - [SNBEP_PCI_UNCORE_IMC] = &snbep_uncore_imc, - [SNBEP_PCI_UNCORE_QPI] = &snbep_uncore_qpi, - [SNBEP_PCI_UNCORE_R2PCIE] = &snbep_uncore_r2pcie, - [SNBEP_PCI_UNCORE_R3QPI] = &snbep_uncore_r3qpi, - NULL, -}; - -static DEFINE_PCI_DEVICE_TABLE(snbep_uncore_pci_ids) = { - { /* Home Agent */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA), - .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_HA, 0), - }, - { /* MC Channel 0 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0), - .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 0), - }, - { /* MC Channel 1 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1), - .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 1), - }, - { /* MC Channel 2 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2), - .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 2), - }, - { /* MC Channel 3 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3), - .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 3), - }, - { /* QPI Port 0 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0), - .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 0), - }, - { /* QPI Port 1 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1), - .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 1), - }, - { /* R2PCIe */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE), - .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R2PCIE, 0), - }, - { /* R3QPI Link 0 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0), - .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 0), - }, - { /* R3QPI Link 1 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1), - .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 1), - }, - { /* QPI Port 0 filter */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c86), - .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, - SNBEP_PCI_QPI_PORT0_FILTER), - }, - { /* QPI Port 0 filter */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c96), - .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, - SNBEP_PCI_QPI_PORT1_FILTER), - }, - { /* end: all zeroes */ } -}; - -static struct pci_driver snbep_uncore_pci_driver = { - .name = "snbep_uncore", - .id_table = snbep_uncore_pci_ids, -}; - -/* - * build pci bus to socket mapping - */ -static int snbep_pci2phy_map_init(int devid) -{ - struct pci_dev *ubox_dev = NULL; - int i, bus, nodeid; - int err = 0; - u32 config = 0; - - while (1) { - /* find the UBOX device */ - ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, ubox_dev); - if (!ubox_dev) - break; - bus = ubox_dev->bus->number; - /* get the Node ID of the local register */ - err = pci_read_config_dword(ubox_dev, 0x40, &config); - if (err) - break; - nodeid = config; - /* get the Node ID mapping */ - err = pci_read_config_dword(ubox_dev, 0x54, &config); - if (err) - break; - /* - * every three bits in the Node ID mapping register maps - * to a particular node. - */ - for (i = 0; i < 8; i++) { - if (nodeid == ((config >> (3 * i)) & 0x7)) { - uncore_pcibus_to_physid[bus] = i; - break; - } - } - } - - if (!err) { - /* - * For PCI bus with no UBOX device, find the next bus - * that has UBOX device and use its mapping. - */ - i = -1; - for (bus = 255; bus >= 0; bus--) { - if (uncore_pcibus_to_physid[bus] >= 0) - i = uncore_pcibus_to_physid[bus]; - else - uncore_pcibus_to_physid[bus] = i; - } - } - - if (ubox_dev) - pci_dev_put(ubox_dev); - - return err ? pcibios_err_to_errno(err) : 0; -} -/* end of Sandy Bridge-EP uncore support */ - -/* IvyTown uncore support */ -static void ivt_uncore_msr_init_box(struct intel_uncore_box *box) -{ - unsigned msr = uncore_msr_box_ctl(box); - if (msr) - wrmsrl(msr, IVT_PMON_BOX_CTL_INT); -} - -static void ivt_uncore_pci_init_box(struct intel_uncore_box *box) -{ - struct pci_dev *pdev = box->pci_dev; - - pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, IVT_PMON_BOX_CTL_INT); -} - -#define IVT_UNCORE_MSR_OPS_COMMON_INIT() \ - .init_box = ivt_uncore_msr_init_box, \ - .disable_box = snbep_uncore_msr_disable_box, \ - .enable_box = snbep_uncore_msr_enable_box, \ - .disable_event = snbep_uncore_msr_disable_event, \ - .enable_event = snbep_uncore_msr_enable_event, \ - .read_counter = uncore_msr_read_counter - -static struct intel_uncore_ops ivt_uncore_msr_ops = { - IVT_UNCORE_MSR_OPS_COMMON_INIT(), -}; - -static struct intel_uncore_ops ivt_uncore_pci_ops = { - .init_box = ivt_uncore_pci_init_box, - .disable_box = snbep_uncore_pci_disable_box, - .enable_box = snbep_uncore_pci_enable_box, - .disable_event = snbep_uncore_pci_disable_event, - .enable_event = snbep_uncore_pci_enable_event, - .read_counter = snbep_uncore_pci_read_counter, -}; - -#define IVT_UNCORE_PCI_COMMON_INIT() \ - .perf_ctr = SNBEP_PCI_PMON_CTR0, \ - .event_ctl = SNBEP_PCI_PMON_CTL0, \ - .event_mask = IVT_PMON_RAW_EVENT_MASK, \ - .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ - .ops = &ivt_uncore_pci_ops, \ - .format_group = &ivt_uncore_format_group - -static struct attribute *ivt_uncore_formats_attr[] = { - &format_attr_event.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_inv.attr, - &format_attr_thresh8.attr, - NULL, -}; - -static struct attribute *ivt_uncore_ubox_formats_attr[] = { - &format_attr_event.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_inv.attr, - &format_attr_thresh5.attr, - NULL, -}; - -static struct attribute *ivt_uncore_cbox_formats_attr[] = { - &format_attr_event.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_tid_en.attr, - &format_attr_thresh8.attr, - &format_attr_filter_tid.attr, - &format_attr_filter_link.attr, - &format_attr_filter_state2.attr, - &format_attr_filter_nid2.attr, - &format_attr_filter_opc2.attr, - NULL, -}; - -static struct attribute *ivt_uncore_pcu_formats_attr[] = { - &format_attr_event_ext.attr, - &format_attr_occ_sel.attr, - &format_attr_edge.attr, - &format_attr_thresh5.attr, - &format_attr_occ_invert.attr, - &format_attr_occ_edge.attr, - &format_attr_filter_band0.attr, - &format_attr_filter_band1.attr, - &format_attr_filter_band2.attr, - &format_attr_filter_band3.attr, - NULL, -}; - -static struct attribute *ivt_uncore_qpi_formats_attr[] = { - &format_attr_event_ext.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_thresh8.attr, - &format_attr_match_rds.attr, - &format_attr_match_rnid30.attr, - &format_attr_match_rnid4.attr, - &format_attr_match_dnid.attr, - &format_attr_match_mc.attr, - &format_attr_match_opc.attr, - &format_attr_match_vnw.attr, - &format_attr_match0.attr, - &format_attr_match1.attr, - &format_attr_mask_rds.attr, - &format_attr_mask_rnid30.attr, - &format_attr_mask_rnid4.attr, - &format_attr_mask_dnid.attr, - &format_attr_mask_mc.attr, - &format_attr_mask_opc.attr, - &format_attr_mask_vnw.attr, - &format_attr_mask0.attr, - &format_attr_mask1.attr, - NULL, -}; - -static struct attribute_group ivt_uncore_format_group = { - .name = "format", - .attrs = ivt_uncore_formats_attr, -}; - -static struct attribute_group ivt_uncore_ubox_format_group = { - .name = "format", - .attrs = ivt_uncore_ubox_formats_attr, -}; - -static struct attribute_group ivt_uncore_cbox_format_group = { - .name = "format", - .attrs = ivt_uncore_cbox_formats_attr, -}; - -static struct attribute_group ivt_uncore_pcu_format_group = { - .name = "format", - .attrs = ivt_uncore_pcu_formats_attr, -}; - -static struct attribute_group ivt_uncore_qpi_format_group = { - .name = "format", - .attrs = ivt_uncore_qpi_formats_attr, -}; - -static struct intel_uncore_type ivt_uncore_ubox = { - .name = "ubox", - .num_counters = 2, - .num_boxes = 1, - .perf_ctr_bits = 44, - .fixed_ctr_bits = 48, - .perf_ctr = SNBEP_U_MSR_PMON_CTR0, - .event_ctl = SNBEP_U_MSR_PMON_CTL0, - .event_mask = IVT_U_MSR_PMON_RAW_EVENT_MASK, - .fixed_ctr = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR, - .fixed_ctl = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL, - .ops = &ivt_uncore_msr_ops, - .format_group = &ivt_uncore_ubox_format_group, -}; - -static struct extra_reg ivt_uncore_cbox_extra_regs[] = { - SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN, - SNBEP_CBO_PMON_CTL_TID_EN, 0x1), - SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2), - - SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4), - SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc), - SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc), - SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4), - SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc), - SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4), - SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc), - SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4), - SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc), - SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18), - SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18), - SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x2136, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18), - SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18), - SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8), - SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10), - SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8), - EVENT_EXTRA_END -}; - -static u64 ivt_cbox_filter_mask(int fields) -{ - u64 mask = 0; - - if (fields & 0x1) - mask |= IVT_CB0_MSR_PMON_BOX_FILTER_TID; - if (fields & 0x2) - mask |= IVT_CB0_MSR_PMON_BOX_FILTER_LINK; - if (fields & 0x4) - mask |= IVT_CB0_MSR_PMON_BOX_FILTER_STATE; - if (fields & 0x8) - mask |= IVT_CB0_MSR_PMON_BOX_FILTER_NID; - if (fields & 0x10) - mask |= IVT_CB0_MSR_PMON_BOX_FILTER_OPC; - - return mask; -} - -static struct event_constraint * -ivt_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) -{ - return __snbep_cbox_get_constraint(box, event, ivt_cbox_filter_mask); -} - -static int ivt_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - struct extra_reg *er; - int idx = 0; - - for (er = ivt_uncore_cbox_extra_regs; er->msr; er++) { - if (er->event != (event->hw.config & er->config_mask)) - continue; - idx |= er->idx; - } - - if (idx) { - reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER + - SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx; - reg1->config = event->attr.config1 & ivt_cbox_filter_mask(idx); - reg1->idx = idx; - } - return 0; -} - -static void ivt_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - - if (reg1->idx != EXTRA_REG_NONE) { - u64 filter = uncore_shared_reg_config(box, 0); - wrmsrl(reg1->reg, filter & 0xffffffff); - wrmsrl(reg1->reg + 6, filter >> 32); - } - - wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); -} - -static struct intel_uncore_ops ivt_uncore_cbox_ops = { - .init_box = ivt_uncore_msr_init_box, - .disable_box = snbep_uncore_msr_disable_box, - .enable_box = snbep_uncore_msr_enable_box, - .disable_event = snbep_uncore_msr_disable_event, - .enable_event = ivt_cbox_enable_event, - .read_counter = uncore_msr_read_counter, - .hw_config = ivt_cbox_hw_config, - .get_constraint = ivt_cbox_get_constraint, - .put_constraint = snbep_cbox_put_constraint, -}; - -static struct intel_uncore_type ivt_uncore_cbox = { - .name = "cbox", - .num_counters = 4, - .num_boxes = 15, - .perf_ctr_bits = 44, - .event_ctl = SNBEP_C0_MSR_PMON_CTL0, - .perf_ctr = SNBEP_C0_MSR_PMON_CTR0, - .event_mask = IVT_CBO_MSR_PMON_RAW_EVENT_MASK, - .box_ctl = SNBEP_C0_MSR_PMON_BOX_CTL, - .msr_offset = SNBEP_CBO_MSR_OFFSET, - .num_shared_regs = 1, - .constraints = snbep_uncore_cbox_constraints, - .ops = &ivt_uncore_cbox_ops, - .format_group = &ivt_uncore_cbox_format_group, -}; - -static struct intel_uncore_ops ivt_uncore_pcu_ops = { - IVT_UNCORE_MSR_OPS_COMMON_INIT(), - .hw_config = snbep_pcu_hw_config, - .get_constraint = snbep_pcu_get_constraint, - .put_constraint = snbep_pcu_put_constraint, -}; - -static struct intel_uncore_type ivt_uncore_pcu = { - .name = "pcu", - .num_counters = 4, - .num_boxes = 1, - .perf_ctr_bits = 48, - .perf_ctr = SNBEP_PCU_MSR_PMON_CTR0, - .event_ctl = SNBEP_PCU_MSR_PMON_CTL0, - .event_mask = IVT_PCU_MSR_PMON_RAW_EVENT_MASK, - .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL, - .num_shared_regs = 1, - .ops = &ivt_uncore_pcu_ops, - .format_group = &ivt_uncore_pcu_format_group, -}; - -static struct intel_uncore_type *ivt_msr_uncores[] = { - &ivt_uncore_ubox, - &ivt_uncore_cbox, - &ivt_uncore_pcu, - NULL, -}; - -static struct intel_uncore_type ivt_uncore_ha = { - .name = "ha", - .num_counters = 4, - .num_boxes = 2, - .perf_ctr_bits = 48, - IVT_UNCORE_PCI_COMMON_INIT(), -}; - -static struct intel_uncore_type ivt_uncore_imc = { - .name = "imc", - .num_counters = 4, - .num_boxes = 8, - .perf_ctr_bits = 48, - .fixed_ctr_bits = 48, - .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, - .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, - IVT_UNCORE_PCI_COMMON_INIT(), -}; - -/* registers in IRP boxes are not properly aligned */ -static unsigned ivt_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4}; -static unsigned ivt_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0}; - -static void ivt_uncore_irp_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct pci_dev *pdev = box->pci_dev; - struct hw_perf_event *hwc = &event->hw; - - pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx], - hwc->config | SNBEP_PMON_CTL_EN); -} - -static void ivt_uncore_irp_disable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct pci_dev *pdev = box->pci_dev; - struct hw_perf_event *hwc = &event->hw; - - pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx], hwc->config); -} - -static u64 ivt_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event) -{ - struct pci_dev *pdev = box->pci_dev; - struct hw_perf_event *hwc = &event->hw; - u64 count = 0; - - pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx], (u32 *)&count); - pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1); - - return count; -} - -static struct intel_uncore_ops ivt_uncore_irp_ops = { - .init_box = ivt_uncore_pci_init_box, - .disable_box = snbep_uncore_pci_disable_box, - .enable_box = snbep_uncore_pci_enable_box, - .disable_event = ivt_uncore_irp_disable_event, - .enable_event = ivt_uncore_irp_enable_event, - .read_counter = ivt_uncore_irp_read_counter, -}; - -static struct intel_uncore_type ivt_uncore_irp = { - .name = "irp", - .num_counters = 4, - .num_boxes = 1, - .perf_ctr_bits = 48, - .event_mask = IVT_PMON_RAW_EVENT_MASK, - .box_ctl = SNBEP_PCI_PMON_BOX_CTL, - .ops = &ivt_uncore_irp_ops, - .format_group = &ivt_uncore_format_group, -}; - -static struct intel_uncore_ops ivt_uncore_qpi_ops = { - .init_box = ivt_uncore_pci_init_box, - .disable_box = snbep_uncore_pci_disable_box, - .enable_box = snbep_uncore_pci_enable_box, - .disable_event = snbep_uncore_pci_disable_event, - .enable_event = snbep_qpi_enable_event, - .read_counter = snbep_uncore_pci_read_counter, - .hw_config = snbep_qpi_hw_config, - .get_constraint = uncore_get_constraint, - .put_constraint = uncore_put_constraint, -}; - -static struct intel_uncore_type ivt_uncore_qpi = { - .name = "qpi", - .num_counters = 4, - .num_boxes = 3, - .perf_ctr_bits = 48, - .perf_ctr = SNBEP_PCI_PMON_CTR0, - .event_ctl = SNBEP_PCI_PMON_CTL0, - .event_mask = IVT_QPI_PCI_PMON_RAW_EVENT_MASK, - .box_ctl = SNBEP_PCI_PMON_BOX_CTL, - .num_shared_regs = 1, - .ops = &ivt_uncore_qpi_ops, - .format_group = &ivt_uncore_qpi_format_group, -}; - -static struct intel_uncore_type ivt_uncore_r2pcie = { - .name = "r2pcie", - .num_counters = 4, - .num_boxes = 1, - .perf_ctr_bits = 44, - .constraints = snbep_uncore_r2pcie_constraints, - IVT_UNCORE_PCI_COMMON_INIT(), -}; - -static struct intel_uncore_type ivt_uncore_r3qpi = { - .name = "r3qpi", - .num_counters = 3, - .num_boxes = 2, - .perf_ctr_bits = 44, - .constraints = snbep_uncore_r3qpi_constraints, - IVT_UNCORE_PCI_COMMON_INIT(), -}; - -enum { - IVT_PCI_UNCORE_HA, - IVT_PCI_UNCORE_IMC, - IVT_PCI_UNCORE_IRP, - IVT_PCI_UNCORE_QPI, - IVT_PCI_UNCORE_R2PCIE, - IVT_PCI_UNCORE_R3QPI, -}; - -static struct intel_uncore_type *ivt_pci_uncores[] = { - [IVT_PCI_UNCORE_HA] = &ivt_uncore_ha, - [IVT_PCI_UNCORE_IMC] = &ivt_uncore_imc, - [IVT_PCI_UNCORE_IRP] = &ivt_uncore_irp, - [IVT_PCI_UNCORE_QPI] = &ivt_uncore_qpi, - [IVT_PCI_UNCORE_R2PCIE] = &ivt_uncore_r2pcie, - [IVT_PCI_UNCORE_R3QPI] = &ivt_uncore_r3qpi, - NULL, -}; - -static DEFINE_PCI_DEVICE_TABLE(ivt_uncore_pci_ids) = { - { /* Home Agent 0 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 0), - }, - { /* Home Agent 1 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 1), - }, - { /* MC0 Channel 0 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 0), - }, - { /* MC0 Channel 1 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 1), - }, - { /* MC0 Channel 3 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 2), - }, - { /* MC0 Channel 4 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 3), - }, - { /* MC1 Channel 0 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 4), - }, - { /* MC1 Channel 1 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 5), - }, - { /* MC1 Channel 3 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 6), - }, - { /* MC1 Channel 4 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 7), - }, - { /* IRP */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe39), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IRP, 0), - }, - { /* QPI0 Port 0 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 0), - }, - { /* QPI0 Port 1 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 1), - }, - { /* QPI1 Port 2 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 2), - }, - { /* R2PCIe */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R2PCIE, 0), - }, - { /* R3QPI0 Link 0 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 0), - }, - { /* R3QPI0 Link 1 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 1), - }, - { /* R3QPI1 Link 2 */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 2), - }, - { /* QPI Port 0 filter */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe86), - .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, - SNBEP_PCI_QPI_PORT0_FILTER), - }, - { /* QPI Port 0 filter */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe96), - .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, - SNBEP_PCI_QPI_PORT1_FILTER), - }, - { /* end: all zeroes */ } -}; - -static struct pci_driver ivt_uncore_pci_driver = { - .name = "ivt_uncore", - .id_table = ivt_uncore_pci_ids, -}; -/* end of IvyTown uncore support */ - /* Nehalem-EX uncore support */ DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5"); DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7"); @@ -3351,18 +1906,10 @@ static int __init uncore_pci_init(void) switch (boot_cpu_data.x86_model) { case 45: /* Sandy Bridge-EP */ - ret = snbep_pci2phy_map_init(0x3ce0); - if (ret) - return ret; - uncore_pci_uncores = snbep_pci_uncores; - uncore_pci_driver = &snbep_uncore_pci_driver; + ret = snbep_uncore_pci_init(); break; case 62: /* IvyTown */ - ret = snbep_pci2phy_map_init(0x0e1e); - if (ret) - return ret; - uncore_pci_uncores = ivt_pci_uncores; - uncore_pci_driver = &ivt_uncore_pci_driver; + ret = ivt_uncore_pci_init(); break; case 42: /* Sandy Bridge */ ret = snb_uncore_pci_init(); @@ -3663,9 +2210,7 @@ static int __init uncore_cpu_init(void) snb_uncore_cpu_init(); break; case 45: /* Sandy Bridge-EP */ - if (snbep_uncore_cbox.num_boxes > max_cores) - snbep_uncore_cbox.num_boxes = max_cores; - uncore_msr_uncores = snbep_msr_uncores; + snbep_uncore_cpu_init(); break; case 46: /* Nehalem-EX */ uncore_nhmex = true; @@ -3677,9 +2222,7 @@ static int __init uncore_cpu_init(void) uncore_msr_uncores = nhmex_msr_uncores; break; case 62: /* IvyTown */ - if (ivt_uncore_cbox.num_boxes > max_cores) - ivt_uncore_cbox.num_boxes = max_cores; - uncore_msr_uncores = ivt_msr_uncores; + ivt_uncore_cpu_init(); break; default: diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index 86699caaacd8..538be93b5f19 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -24,164 +24,6 @@ #define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff) -/* SNB-EP Box level control */ -#define SNBEP_PMON_BOX_CTL_RST_CTRL (1 << 0) -#define SNBEP_PMON_BOX_CTL_RST_CTRS (1 << 1) -#define SNBEP_PMON_BOX_CTL_FRZ (1 << 8) -#define SNBEP_PMON_BOX_CTL_FRZ_EN (1 << 16) -#define SNBEP_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \ - SNBEP_PMON_BOX_CTL_RST_CTRS | \ - SNBEP_PMON_BOX_CTL_FRZ_EN) -/* SNB-EP event control */ -#define SNBEP_PMON_CTL_EV_SEL_MASK 0x000000ff -#define SNBEP_PMON_CTL_UMASK_MASK 0x0000ff00 -#define SNBEP_PMON_CTL_RST (1 << 17) -#define SNBEP_PMON_CTL_EDGE_DET (1 << 18) -#define SNBEP_PMON_CTL_EV_SEL_EXT (1 << 21) -#define SNBEP_PMON_CTL_EN (1 << 22) -#define SNBEP_PMON_CTL_INVERT (1 << 23) -#define SNBEP_PMON_CTL_TRESH_MASK 0xff000000 -#define SNBEP_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \ - SNBEP_PMON_CTL_UMASK_MASK | \ - SNBEP_PMON_CTL_EDGE_DET | \ - SNBEP_PMON_CTL_INVERT | \ - SNBEP_PMON_CTL_TRESH_MASK) - -/* SNB-EP Ubox event control */ -#define SNBEP_U_MSR_PMON_CTL_TRESH_MASK 0x1f000000 -#define SNBEP_U_MSR_PMON_RAW_EVENT_MASK \ - (SNBEP_PMON_CTL_EV_SEL_MASK | \ - SNBEP_PMON_CTL_UMASK_MASK | \ - SNBEP_PMON_CTL_EDGE_DET | \ - SNBEP_PMON_CTL_INVERT | \ - SNBEP_U_MSR_PMON_CTL_TRESH_MASK) - -#define SNBEP_CBO_PMON_CTL_TID_EN (1 << 19) -#define SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK (SNBEP_PMON_RAW_EVENT_MASK | \ - SNBEP_CBO_PMON_CTL_TID_EN) - -/* SNB-EP PCU event control */ -#define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK 0x0000c000 -#define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK 0x1f000000 -#define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT (1 << 30) -#define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET (1 << 31) -#define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK \ - (SNBEP_PMON_CTL_EV_SEL_MASK | \ - SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \ - SNBEP_PMON_CTL_EDGE_DET | \ - SNBEP_PMON_CTL_EV_SEL_EXT | \ - SNBEP_PMON_CTL_INVERT | \ - SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \ - SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \ - SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET) - -#define SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK \ - (SNBEP_PMON_RAW_EVENT_MASK | \ - SNBEP_PMON_CTL_EV_SEL_EXT) - -/* SNB-EP pci control register */ -#define SNBEP_PCI_PMON_BOX_CTL 0xf4 -#define SNBEP_PCI_PMON_CTL0 0xd8 -/* SNB-EP pci counter register */ -#define SNBEP_PCI_PMON_CTR0 0xa0 - -/* SNB-EP home agent register */ -#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0 0x40 -#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1 0x44 -#define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH 0x48 -/* SNB-EP memory controller register */ -#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL 0xf0 -#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR 0xd0 -/* SNB-EP QPI register */ -#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0 0x228 -#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1 0x22c -#define SNBEP_Q_Py_PCI_PMON_PKT_MASK0 0x238 -#define SNBEP_Q_Py_PCI_PMON_PKT_MASK1 0x23c - -/* SNB-EP Ubox register */ -#define SNBEP_U_MSR_PMON_CTR0 0xc16 -#define SNBEP_U_MSR_PMON_CTL0 0xc10 - -#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL 0xc08 -#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR 0xc09 - -/* SNB-EP Cbo register */ -#define SNBEP_C0_MSR_PMON_CTR0 0xd16 -#define SNBEP_C0_MSR_PMON_CTL0 0xd10 -#define SNBEP_C0_MSR_PMON_BOX_CTL 0xd04 -#define SNBEP_C0_MSR_PMON_BOX_FILTER 0xd14 -#define SNBEP_CBO_MSR_OFFSET 0x20 - -#define SNBEP_CB0_MSR_PMON_BOX_FILTER_TID 0x1f -#define SNBEP_CB0_MSR_PMON_BOX_FILTER_NID 0x3fc00 -#define SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE 0x7c0000 -#define SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC 0xff800000 - -#define SNBEP_CBO_EVENT_EXTRA_REG(e, m, i) { \ - .event = (e), \ - .msr = SNBEP_C0_MSR_PMON_BOX_FILTER, \ - .config_mask = (m), \ - .idx = (i) \ -} - -/* SNB-EP PCU register */ -#define SNBEP_PCU_MSR_PMON_CTR0 0xc36 -#define SNBEP_PCU_MSR_PMON_CTL0 0xc30 -#define SNBEP_PCU_MSR_PMON_BOX_CTL 0xc24 -#define SNBEP_PCU_MSR_PMON_BOX_FILTER 0xc34 -#define SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK 0xffffffff -#define SNBEP_PCU_MSR_CORE_C3_CTR 0x3fc -#define SNBEP_PCU_MSR_CORE_C6_CTR 0x3fd - -/* IVT event control */ -#define IVT_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \ - SNBEP_PMON_BOX_CTL_RST_CTRS) -#define IVT_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \ - SNBEP_PMON_CTL_UMASK_MASK | \ - SNBEP_PMON_CTL_EDGE_DET | \ - SNBEP_PMON_CTL_TRESH_MASK) -/* IVT Ubox */ -#define IVT_U_MSR_PMON_GLOBAL_CTL 0xc00 -#define IVT_U_PMON_GLOBAL_FRZ_ALL (1 << 31) -#define IVT_U_PMON_GLOBAL_UNFRZ_ALL (1 << 29) - -#define IVT_U_MSR_PMON_RAW_EVENT_MASK \ - (SNBEP_PMON_CTL_EV_SEL_MASK | \ - SNBEP_PMON_CTL_UMASK_MASK | \ - SNBEP_PMON_CTL_EDGE_DET | \ - SNBEP_U_MSR_PMON_CTL_TRESH_MASK) -/* IVT Cbo */ -#define IVT_CBO_MSR_PMON_RAW_EVENT_MASK (IVT_PMON_RAW_EVENT_MASK | \ - SNBEP_CBO_PMON_CTL_TID_EN) - -#define IVT_CB0_MSR_PMON_BOX_FILTER_TID (0x1fULL << 0) -#define IVT_CB0_MSR_PMON_BOX_FILTER_LINK (0xfULL << 5) -#define IVT_CB0_MSR_PMON_BOX_FILTER_STATE (0x3fULL << 17) -#define IVT_CB0_MSR_PMON_BOX_FILTER_NID (0xffffULL << 32) -#define IVT_CB0_MSR_PMON_BOX_FILTER_OPC (0x1ffULL << 52) -#define IVT_CB0_MSR_PMON_BOX_FILTER_C6 (0x1ULL << 61) -#define IVT_CB0_MSR_PMON_BOX_FILTER_NC (0x1ULL << 62) -#define IVT_CB0_MSR_PMON_BOX_FILTER_IOSC (0x1ULL << 63) - -/* IVT home agent */ -#define IVT_HA_PCI_PMON_CTL_Q_OCC_RST (1 << 16) -#define IVT_HA_PCI_PMON_RAW_EVENT_MASK \ - (IVT_PMON_RAW_EVENT_MASK | \ - IVT_HA_PCI_PMON_CTL_Q_OCC_RST) -/* IVT PCU */ -#define IVT_PCU_MSR_PMON_RAW_EVENT_MASK \ - (SNBEP_PMON_CTL_EV_SEL_MASK | \ - SNBEP_PMON_CTL_EV_SEL_EXT | \ - SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \ - SNBEP_PMON_CTL_EDGE_DET | \ - SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \ - SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \ - SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET) -/* IVT QPI */ -#define IVT_QPI_PCI_PMON_RAW_EVENT_MASK \ - (IVT_PMON_RAW_EVENT_MASK | \ - SNBEP_PMON_CTL_EV_SEL_EXT) - /* NHM-EX event control */ #define NHMEX_PMON_CTL_EV_SEL_MASK 0x000000ff #define NHMEX_PMON_CTL_UMASK_MASK 0x0000ff00 @@ -666,3 +508,9 @@ int ivb_uncore_pci_init(void); int hsw_uncore_pci_init(void); void snb_uncore_cpu_init(void); void nhm_uncore_cpu_init(void); + +/* perf_event_intel_uncore_snbep.c */ +int snbep_uncore_pci_init(void); +void snbep_uncore_cpu_init(void); +int ivt_uncore_pci_init(void); +void ivt_uncore_cpu_init(void); diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c new file mode 100644 index 000000000000..30468f434e9e --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c @@ -0,0 +1,1644 @@ +/* SandyBridge-EP/IvyTown uncore support */ +#include "perf_event_intel_uncore.h" + + +/* SNB-EP Box level control */ +#define SNBEP_PMON_BOX_CTL_RST_CTRL (1 << 0) +#define SNBEP_PMON_BOX_CTL_RST_CTRS (1 << 1) +#define SNBEP_PMON_BOX_CTL_FRZ (1 << 8) +#define SNBEP_PMON_BOX_CTL_FRZ_EN (1 << 16) +#define SNBEP_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \ + SNBEP_PMON_BOX_CTL_RST_CTRS | \ + SNBEP_PMON_BOX_CTL_FRZ_EN) +/* SNB-EP event control */ +#define SNBEP_PMON_CTL_EV_SEL_MASK 0x000000ff +#define SNBEP_PMON_CTL_UMASK_MASK 0x0000ff00 +#define SNBEP_PMON_CTL_RST (1 << 17) +#define SNBEP_PMON_CTL_EDGE_DET (1 << 18) +#define SNBEP_PMON_CTL_EV_SEL_EXT (1 << 21) +#define SNBEP_PMON_CTL_EN (1 << 22) +#define SNBEP_PMON_CTL_INVERT (1 << 23) +#define SNBEP_PMON_CTL_TRESH_MASK 0xff000000 +#define SNBEP_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \ + SNBEP_PMON_CTL_UMASK_MASK | \ + SNBEP_PMON_CTL_EDGE_DET | \ + SNBEP_PMON_CTL_INVERT | \ + SNBEP_PMON_CTL_TRESH_MASK) + +/* SNB-EP Ubox event control */ +#define SNBEP_U_MSR_PMON_CTL_TRESH_MASK 0x1f000000 +#define SNBEP_U_MSR_PMON_RAW_EVENT_MASK \ + (SNBEP_PMON_CTL_EV_SEL_MASK | \ + SNBEP_PMON_CTL_UMASK_MASK | \ + SNBEP_PMON_CTL_EDGE_DET | \ + SNBEP_PMON_CTL_INVERT | \ + SNBEP_U_MSR_PMON_CTL_TRESH_MASK) + +#define SNBEP_CBO_PMON_CTL_TID_EN (1 << 19) +#define SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK (SNBEP_PMON_RAW_EVENT_MASK | \ + SNBEP_CBO_PMON_CTL_TID_EN) + +/* SNB-EP PCU event control */ +#define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK 0x0000c000 +#define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK 0x1f000000 +#define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT (1 << 30) +#define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET (1 << 31) +#define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK \ + (SNBEP_PMON_CTL_EV_SEL_MASK | \ + SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \ + SNBEP_PMON_CTL_EDGE_DET | \ + SNBEP_PMON_CTL_EV_SEL_EXT | \ + SNBEP_PMON_CTL_INVERT | \ + SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \ + SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \ + SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET) + +#define SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK \ + (SNBEP_PMON_RAW_EVENT_MASK | \ + SNBEP_PMON_CTL_EV_SEL_EXT) + +/* SNB-EP pci control register */ +#define SNBEP_PCI_PMON_BOX_CTL 0xf4 +#define SNBEP_PCI_PMON_CTL0 0xd8 +/* SNB-EP pci counter register */ +#define SNBEP_PCI_PMON_CTR0 0xa0 + +/* SNB-EP home agent register */ +#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0 0x40 +#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1 0x44 +#define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH 0x48 +/* SNB-EP memory controller register */ +#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL 0xf0 +#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR 0xd0 +/* SNB-EP QPI register */ +#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0 0x228 +#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1 0x22c +#define SNBEP_Q_Py_PCI_PMON_PKT_MASK0 0x238 +#define SNBEP_Q_Py_PCI_PMON_PKT_MASK1 0x23c + +/* SNB-EP Ubox register */ +#define SNBEP_U_MSR_PMON_CTR0 0xc16 +#define SNBEP_U_MSR_PMON_CTL0 0xc10 + +#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL 0xc08 +#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR 0xc09 + +/* SNB-EP Cbo register */ +#define SNBEP_C0_MSR_PMON_CTR0 0xd16 +#define SNBEP_C0_MSR_PMON_CTL0 0xd10 +#define SNBEP_C0_MSR_PMON_BOX_CTL 0xd04 +#define SNBEP_C0_MSR_PMON_BOX_FILTER 0xd14 +#define SNBEP_CBO_MSR_OFFSET 0x20 + +#define SNBEP_CB0_MSR_PMON_BOX_FILTER_TID 0x1f +#define SNBEP_CB0_MSR_PMON_BOX_FILTER_NID 0x3fc00 +#define SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE 0x7c0000 +#define SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC 0xff800000 + +#define SNBEP_CBO_EVENT_EXTRA_REG(e, m, i) { \ + .event = (e), \ + .msr = SNBEP_C0_MSR_PMON_BOX_FILTER, \ + .config_mask = (m), \ + .idx = (i) \ +} + +/* SNB-EP PCU register */ +#define SNBEP_PCU_MSR_PMON_CTR0 0xc36 +#define SNBEP_PCU_MSR_PMON_CTL0 0xc30 +#define SNBEP_PCU_MSR_PMON_BOX_CTL 0xc24 +#define SNBEP_PCU_MSR_PMON_BOX_FILTER 0xc34 +#define SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK 0xffffffff +#define SNBEP_PCU_MSR_CORE_C3_CTR 0x3fc +#define SNBEP_PCU_MSR_CORE_C6_CTR 0x3fd + +/* IVT event control */ +#define IVT_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \ + SNBEP_PMON_BOX_CTL_RST_CTRS) +#define IVT_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \ + SNBEP_PMON_CTL_UMASK_MASK | \ + SNBEP_PMON_CTL_EDGE_DET | \ + SNBEP_PMON_CTL_TRESH_MASK) +/* IVT Ubox */ +#define IVT_U_MSR_PMON_GLOBAL_CTL 0xc00 +#define IVT_U_PMON_GLOBAL_FRZ_ALL (1 << 31) +#define IVT_U_PMON_GLOBAL_UNFRZ_ALL (1 << 29) + +#define IVT_U_MSR_PMON_RAW_EVENT_MASK \ + (SNBEP_PMON_CTL_EV_SEL_MASK | \ + SNBEP_PMON_CTL_UMASK_MASK | \ + SNBEP_PMON_CTL_EDGE_DET | \ + SNBEP_U_MSR_PMON_CTL_TRESH_MASK) +/* IVT Cbo */ +#define IVT_CBO_MSR_PMON_RAW_EVENT_MASK (IVT_PMON_RAW_EVENT_MASK | \ + SNBEP_CBO_PMON_CTL_TID_EN) + +#define IVT_CB0_MSR_PMON_BOX_FILTER_TID (0x1fULL << 0) +#define IVT_CB0_MSR_PMON_BOX_FILTER_LINK (0xfULL << 5) +#define IVT_CB0_MSR_PMON_BOX_FILTER_STATE (0x3fULL << 17) +#define IVT_CB0_MSR_PMON_BOX_FILTER_NID (0xffffULL << 32) +#define IVT_CB0_MSR_PMON_BOX_FILTER_OPC (0x1ffULL << 52) +#define IVT_CB0_MSR_PMON_BOX_FILTER_C6 (0x1ULL << 61) +#define IVT_CB0_MSR_PMON_BOX_FILTER_NC (0x1ULL << 62) +#define IVT_CB0_MSR_PMON_BOX_FILTER_IOSC (0x1ULL << 63) + +/* IVT home agent */ +#define IVT_HA_PCI_PMON_CTL_Q_OCC_RST (1 << 16) +#define IVT_HA_PCI_PMON_RAW_EVENT_MASK \ + (IVT_PMON_RAW_EVENT_MASK | \ + IVT_HA_PCI_PMON_CTL_Q_OCC_RST) +/* IVT PCU */ +#define IVT_PCU_MSR_PMON_RAW_EVENT_MASK \ + (SNBEP_PMON_CTL_EV_SEL_MASK | \ + SNBEP_PMON_CTL_EV_SEL_EXT | \ + SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \ + SNBEP_PMON_CTL_EDGE_DET | \ + SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \ + SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \ + SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET) +/* IVT QPI */ +#define IVT_QPI_PCI_PMON_RAW_EVENT_MASK \ + (IVT_PMON_RAW_EVENT_MASK | \ + SNBEP_PMON_CTL_EV_SEL_EXT) + +#define __BITS_VALUE(x, i, n) ((typeof(x))(((x) >> ((i) * (n))) & \ + ((1ULL << (n)) - 1))) + +DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); +DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21"); +DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); +DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); +DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19"); +DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); +DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31"); +DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28"); +DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15"); +DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30"); +DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51"); +DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4"); +DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8"); +DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17"); +DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47"); +DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22"); +DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22"); +DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31"); +DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60"); +DEFINE_UNCORE_FORMAT_ATTR(filter_band0, filter_band0, "config1:0-7"); +DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15"); +DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23"); +DEFINE_UNCORE_FORMAT_ATTR(filter_band3, filter_band3, "config1:24-31"); +DEFINE_UNCORE_FORMAT_ATTR(match_rds, match_rds, "config1:48-51"); +DEFINE_UNCORE_FORMAT_ATTR(match_rnid30, match_rnid30, "config1:32-35"); +DEFINE_UNCORE_FORMAT_ATTR(match_rnid4, match_rnid4, "config1:31"); +DEFINE_UNCORE_FORMAT_ATTR(match_dnid, match_dnid, "config1:13-17"); +DEFINE_UNCORE_FORMAT_ATTR(match_mc, match_mc, "config1:9-12"); +DEFINE_UNCORE_FORMAT_ATTR(match_opc, match_opc, "config1:5-8"); +DEFINE_UNCORE_FORMAT_ATTR(match_vnw, match_vnw, "config1:3-4"); +DEFINE_UNCORE_FORMAT_ATTR(match0, match0, "config1:0-31"); +DEFINE_UNCORE_FORMAT_ATTR(match1, match1, "config1:32-63"); +DEFINE_UNCORE_FORMAT_ATTR(mask_rds, mask_rds, "config2:48-51"); +DEFINE_UNCORE_FORMAT_ATTR(mask_rnid30, mask_rnid30, "config2:32-35"); +DEFINE_UNCORE_FORMAT_ATTR(mask_rnid4, mask_rnid4, "config2:31"); +DEFINE_UNCORE_FORMAT_ATTR(mask_dnid, mask_dnid, "config2:13-17"); +DEFINE_UNCORE_FORMAT_ATTR(mask_mc, mask_mc, "config2:9-12"); +DEFINE_UNCORE_FORMAT_ATTR(mask_opc, mask_opc, "config2:5-8"); +DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4"); +DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31"); +DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63"); + +static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + int box_ctl = uncore_pci_box_ctl(box); + u32 config = 0; + + if (!pci_read_config_dword(pdev, box_ctl, &config)) { + config |= SNBEP_PMON_BOX_CTL_FRZ; + pci_write_config_dword(pdev, box_ctl, config); + } +} + +static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + int box_ctl = uncore_pci_box_ctl(box); + u32 config = 0; + + if (!pci_read_config_dword(pdev, box_ctl, &config)) { + config &= ~SNBEP_PMON_BOX_CTL_FRZ; + pci_write_config_dword(pdev, box_ctl, config); + } +} + +static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + + pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); +} + +static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + + pci_write_config_dword(pdev, hwc->config_base, hwc->config); +} + +static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + u64 count = 0; + + pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count); + pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1); + + return count; +} + +static void snbep_uncore_pci_init_box(struct intel_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + + pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, SNBEP_PMON_BOX_CTL_INT); +} + +static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box) +{ + u64 config; + unsigned msr; + + msr = uncore_msr_box_ctl(box); + if (msr) { + rdmsrl(msr, config); + config |= SNBEP_PMON_BOX_CTL_FRZ; + wrmsrl(msr, config); + } +} + +static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box) +{ + u64 config; + unsigned msr; + + msr = uncore_msr_box_ctl(box); + if (msr) { + rdmsrl(msr, config); + config &= ~SNBEP_PMON_BOX_CTL_FRZ; + wrmsrl(msr, config); + } +} + +static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + + if (reg1->idx != EXTRA_REG_NONE) + wrmsrl(reg1->reg, uncore_shared_reg_config(box, 0)); + + wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); +} + +static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box, + struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + wrmsrl(hwc->config_base, hwc->config); +} + +static void snbep_uncore_msr_init_box(struct intel_uncore_box *box) +{ + unsigned msr = uncore_msr_box_ctl(box); + + if (msr) + wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT); +} + +static struct attribute *snbep_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh8.attr, + NULL, +}; + +static struct attribute *snbep_uncore_ubox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, + NULL, +}; + +static struct attribute *snbep_uncore_cbox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_tid_en.attr, + &format_attr_inv.attr, + &format_attr_thresh8.attr, + &format_attr_filter_tid.attr, + &format_attr_filter_nid.attr, + &format_attr_filter_state.attr, + &format_attr_filter_opc.attr, + NULL, +}; + +static struct attribute *snbep_uncore_pcu_formats_attr[] = { + &format_attr_event_ext.attr, + &format_attr_occ_sel.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, + &format_attr_occ_invert.attr, + &format_attr_occ_edge.attr, + &format_attr_filter_band0.attr, + &format_attr_filter_band1.attr, + &format_attr_filter_band2.attr, + &format_attr_filter_band3.attr, + NULL, +}; + +static struct attribute *snbep_uncore_qpi_formats_attr[] = { + &format_attr_event_ext.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh8.attr, + &format_attr_match_rds.attr, + &format_attr_match_rnid30.attr, + &format_attr_match_rnid4.attr, + &format_attr_match_dnid.attr, + &format_attr_match_mc.attr, + &format_attr_match_opc.attr, + &format_attr_match_vnw.attr, + &format_attr_match0.attr, + &format_attr_match1.attr, + &format_attr_mask_rds.attr, + &format_attr_mask_rnid30.attr, + &format_attr_mask_rnid4.attr, + &format_attr_mask_dnid.attr, + &format_attr_mask_mc.attr, + &format_attr_mask_opc.attr, + &format_attr_mask_vnw.attr, + &format_attr_mask0.attr, + &format_attr_mask1.attr, + NULL, +}; + +static struct uncore_event_desc snbep_uncore_imc_events[] = { + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"), + INTEL_UNCORE_EVENT_DESC(cas_count_read, "event=0x04,umask=0x03"), + INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"), + { /* end: all zeroes */ }, +}; + +static struct uncore_event_desc snbep_uncore_qpi_events[] = { + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0x14"), + INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"), + INTEL_UNCORE_EVENT_DESC(drs_data, "event=0x102,umask=0x08"), + INTEL_UNCORE_EVENT_DESC(ncb_data, "event=0x103,umask=0x04"), + { /* end: all zeroes */ }, +}; + +static struct attribute_group snbep_uncore_format_group = { + .name = "format", + .attrs = snbep_uncore_formats_attr, +}; + +static struct attribute_group snbep_uncore_ubox_format_group = { + .name = "format", + .attrs = snbep_uncore_ubox_formats_attr, +}; + +static struct attribute_group snbep_uncore_cbox_format_group = { + .name = "format", + .attrs = snbep_uncore_cbox_formats_attr, +}; + +static struct attribute_group snbep_uncore_pcu_format_group = { + .name = "format", + .attrs = snbep_uncore_pcu_formats_attr, +}; + +static struct attribute_group snbep_uncore_qpi_format_group = { + .name = "format", + .attrs = snbep_uncore_qpi_formats_attr, +}; + +#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \ + .init_box = snbep_uncore_msr_init_box, \ + .disable_box = snbep_uncore_msr_disable_box, \ + .enable_box = snbep_uncore_msr_enable_box, \ + .disable_event = snbep_uncore_msr_disable_event, \ + .enable_event = snbep_uncore_msr_enable_event, \ + .read_counter = uncore_msr_read_counter + +static struct intel_uncore_ops snbep_uncore_msr_ops = { + SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), +}; + +#define SNBEP_UNCORE_PCI_OPS_COMMON_INIT() \ + .init_box = snbep_uncore_pci_init_box, \ + .disable_box = snbep_uncore_pci_disable_box, \ + .enable_box = snbep_uncore_pci_enable_box, \ + .disable_event = snbep_uncore_pci_disable_event, \ + .read_counter = snbep_uncore_pci_read_counter + +static struct intel_uncore_ops snbep_uncore_pci_ops = { + SNBEP_UNCORE_PCI_OPS_COMMON_INIT(), + .enable_event = snbep_uncore_pci_enable_event, \ +}; + +static struct event_constraint snbep_uncore_cbox_constraints[] = { + UNCORE_EVENT_CONSTRAINT(0x01, 0x1), + UNCORE_EVENT_CONSTRAINT(0x02, 0x3), + UNCORE_EVENT_CONSTRAINT(0x04, 0x3), + UNCORE_EVENT_CONSTRAINT(0x05, 0x3), + UNCORE_EVENT_CONSTRAINT(0x07, 0x3), + UNCORE_EVENT_CONSTRAINT(0x09, 0x3), + UNCORE_EVENT_CONSTRAINT(0x11, 0x1), + UNCORE_EVENT_CONSTRAINT(0x12, 0x3), + UNCORE_EVENT_CONSTRAINT(0x13, 0x3), + UNCORE_EVENT_CONSTRAINT(0x1b, 0xc), + UNCORE_EVENT_CONSTRAINT(0x1c, 0xc), + UNCORE_EVENT_CONSTRAINT(0x1d, 0xc), + UNCORE_EVENT_CONSTRAINT(0x1e, 0xc), + EVENT_CONSTRAINT_OVERLAP(0x1f, 0xe, 0xff), + UNCORE_EVENT_CONSTRAINT(0x21, 0x3), + UNCORE_EVENT_CONSTRAINT(0x23, 0x3), + UNCORE_EVENT_CONSTRAINT(0x31, 0x3), + UNCORE_EVENT_CONSTRAINT(0x32, 0x3), + UNCORE_EVENT_CONSTRAINT(0x33, 0x3), + UNCORE_EVENT_CONSTRAINT(0x34, 0x3), + UNCORE_EVENT_CONSTRAINT(0x35, 0x3), + UNCORE_EVENT_CONSTRAINT(0x36, 0x1), + UNCORE_EVENT_CONSTRAINT(0x37, 0x3), + UNCORE_EVENT_CONSTRAINT(0x38, 0x3), + UNCORE_EVENT_CONSTRAINT(0x39, 0x3), + UNCORE_EVENT_CONSTRAINT(0x3b, 0x1), + EVENT_CONSTRAINT_END +}; + +static struct event_constraint snbep_uncore_r2pcie_constraints[] = { + UNCORE_EVENT_CONSTRAINT(0x10, 0x3), + UNCORE_EVENT_CONSTRAINT(0x11, 0x3), + UNCORE_EVENT_CONSTRAINT(0x12, 0x1), + UNCORE_EVENT_CONSTRAINT(0x23, 0x3), + UNCORE_EVENT_CONSTRAINT(0x24, 0x3), + UNCORE_EVENT_CONSTRAINT(0x25, 0x3), + UNCORE_EVENT_CONSTRAINT(0x26, 0x3), + UNCORE_EVENT_CONSTRAINT(0x32, 0x3), + UNCORE_EVENT_CONSTRAINT(0x33, 0x3), + UNCORE_EVENT_CONSTRAINT(0x34, 0x3), + EVENT_CONSTRAINT_END +}; + +static struct event_constraint snbep_uncore_r3qpi_constraints[] = { + UNCORE_EVENT_CONSTRAINT(0x10, 0x3), + UNCORE_EVENT_CONSTRAINT(0x11, 0x3), + UNCORE_EVENT_CONSTRAINT(0x12, 0x3), + UNCORE_EVENT_CONSTRAINT(0x13, 0x1), + UNCORE_EVENT_CONSTRAINT(0x20, 0x3), + UNCORE_EVENT_CONSTRAINT(0x21, 0x3), + UNCORE_EVENT_CONSTRAINT(0x22, 0x3), + UNCORE_EVENT_CONSTRAINT(0x23, 0x3), + UNCORE_EVENT_CONSTRAINT(0x24, 0x3), + UNCORE_EVENT_CONSTRAINT(0x25, 0x3), + UNCORE_EVENT_CONSTRAINT(0x26, 0x3), + UNCORE_EVENT_CONSTRAINT(0x28, 0x3), + UNCORE_EVENT_CONSTRAINT(0x29, 0x3), + UNCORE_EVENT_CONSTRAINT(0x2a, 0x3), + UNCORE_EVENT_CONSTRAINT(0x2b, 0x3), + UNCORE_EVENT_CONSTRAINT(0x2c, 0x3), + UNCORE_EVENT_CONSTRAINT(0x2d, 0x3), + UNCORE_EVENT_CONSTRAINT(0x2e, 0x3), + UNCORE_EVENT_CONSTRAINT(0x2f, 0x3), + UNCORE_EVENT_CONSTRAINT(0x30, 0x3), + UNCORE_EVENT_CONSTRAINT(0x31, 0x3), + UNCORE_EVENT_CONSTRAINT(0x32, 0x3), + UNCORE_EVENT_CONSTRAINT(0x33, 0x3), + UNCORE_EVENT_CONSTRAINT(0x34, 0x3), + UNCORE_EVENT_CONSTRAINT(0x36, 0x3), + UNCORE_EVENT_CONSTRAINT(0x37, 0x3), + UNCORE_EVENT_CONSTRAINT(0x38, 0x3), + UNCORE_EVENT_CONSTRAINT(0x39, 0x3), + EVENT_CONSTRAINT_END +}; + +static struct intel_uncore_type snbep_uncore_ubox = { + .name = "ubox", + .num_counters = 2, + .num_boxes = 1, + .perf_ctr_bits = 44, + .fixed_ctr_bits = 48, + .perf_ctr = SNBEP_U_MSR_PMON_CTR0, + .event_ctl = SNBEP_U_MSR_PMON_CTL0, + .event_mask = SNBEP_U_MSR_PMON_RAW_EVENT_MASK, + .fixed_ctr = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR, + .fixed_ctl = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL, + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_ubox_format_group, +}; + +static struct extra_reg snbep_uncore_cbox_extra_regs[] = { + SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN, + SNBEP_CBO_PMON_CTL_TID_EN, 0x1), + SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4), + SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6), + SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4), + SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6), + SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4), + SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6), + SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6), + SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0xa), + SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0xa), + SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x2), + SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x2), + SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x2), + SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x2), + SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0xa), + SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0xa), + SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x2), + SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x2), + SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x2), + SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x2), + EVENT_EXTRA_END +}; + +static void snbep_cbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + struct intel_uncore_extra_reg *er = &box->shared_regs[0]; + int i; + + if (uncore_box_is_fake(box)) + return; + + for (i = 0; i < 5; i++) { + if (reg1->alloc & (0x1 << i)) + atomic_sub(1 << (i * 6), &er->ref); + } + reg1->alloc = 0; +} + +static struct event_constraint * +__snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event, + u64 (*cbox_filter_mask)(int fields)) +{ + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + struct intel_uncore_extra_reg *er = &box->shared_regs[0]; + int i, alloc = 0; + unsigned long flags; + u64 mask; + + if (reg1->idx == EXTRA_REG_NONE) + return NULL; + + raw_spin_lock_irqsave(&er->lock, flags); + for (i = 0; i < 5; i++) { + if (!(reg1->idx & (0x1 << i))) + continue; + if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i))) + continue; + + mask = cbox_filter_mask(0x1 << i); + if (!__BITS_VALUE(atomic_read(&er->ref), i, 6) || + !((reg1->config ^ er->config) & mask)) { + atomic_add(1 << (i * 6), &er->ref); + er->config &= ~mask; + er->config |= reg1->config & mask; + alloc |= (0x1 << i); + } else { + break; + } + } + raw_spin_unlock_irqrestore(&er->lock, flags); + if (i < 5) + goto fail; + + if (!uncore_box_is_fake(box)) + reg1->alloc |= alloc; + + return NULL; +fail: + for (; i >= 0; i--) { + if (alloc & (0x1 << i)) + atomic_sub(1 << (i * 6), &er->ref); + } + return &uncore_constraint_empty; +} + +static u64 snbep_cbox_filter_mask(int fields) +{ + u64 mask = 0; + + if (fields & 0x1) + mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_TID; + if (fields & 0x2) + mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_NID; + if (fields & 0x4) + mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE; + if (fields & 0x8) + mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC; + + return mask; +} + +static struct event_constraint * +snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) +{ + return __snbep_cbox_get_constraint(box, event, snbep_cbox_filter_mask); +} + +static int snbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + struct extra_reg *er; + int idx = 0; + + for (er = snbep_uncore_cbox_extra_regs; er->msr; er++) { + if (er->event != (event->hw.config & er->config_mask)) + continue; + idx |= er->idx; + } + + if (idx) { + reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER + + SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx; + reg1->config = event->attr.config1 & snbep_cbox_filter_mask(idx); + reg1->idx = idx; + } + return 0; +} + +static struct intel_uncore_ops snbep_uncore_cbox_ops = { + SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), + .hw_config = snbep_cbox_hw_config, + .get_constraint = snbep_cbox_get_constraint, + .put_constraint = snbep_cbox_put_constraint, +}; + +static struct intel_uncore_type snbep_uncore_cbox = { + .name = "cbox", + .num_counters = 4, + .num_boxes = 8, + .perf_ctr_bits = 44, + .event_ctl = SNBEP_C0_MSR_PMON_CTL0, + .perf_ctr = SNBEP_C0_MSR_PMON_CTR0, + .event_mask = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK, + .box_ctl = SNBEP_C0_MSR_PMON_BOX_CTL, + .msr_offset = SNBEP_CBO_MSR_OFFSET, + .num_shared_regs = 1, + .constraints = snbep_uncore_cbox_constraints, + .ops = &snbep_uncore_cbox_ops, + .format_group = &snbep_uncore_cbox_format_group, +}; + +static u64 snbep_pcu_alter_er(struct perf_event *event, int new_idx, bool modify) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + u64 config = reg1->config; + + if (new_idx > reg1->idx) + config <<= 8 * (new_idx - reg1->idx); + else + config >>= 8 * (reg1->idx - new_idx); + + if (modify) { + hwc->config += new_idx - reg1->idx; + reg1->config = config; + reg1->idx = new_idx; + } + return config; +} + +static struct event_constraint * +snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + struct intel_uncore_extra_reg *er = &box->shared_regs[0]; + unsigned long flags; + int idx = reg1->idx; + u64 mask, config1 = reg1->config; + bool ok = false; + + if (reg1->idx == EXTRA_REG_NONE || + (!uncore_box_is_fake(box) && reg1->alloc)) + return NULL; +again: + mask = 0xffULL << (idx * 8); + raw_spin_lock_irqsave(&er->lock, flags); + if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) || + !((config1 ^ er->config) & mask)) { + atomic_add(1 << (idx * 8), &er->ref); + er->config &= ~mask; + er->config |= config1 & mask; + ok = true; + } + raw_spin_unlock_irqrestore(&er->lock, flags); + + if (!ok) { + idx = (idx + 1) % 4; + if (idx != reg1->idx) { + config1 = snbep_pcu_alter_er(event, idx, false); + goto again; + } + return &uncore_constraint_empty; + } + + if (!uncore_box_is_fake(box)) { + if (idx != reg1->idx) + snbep_pcu_alter_er(event, idx, true); + reg1->alloc = 1; + } + return NULL; +} + +static void snbep_pcu_put_constraint(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + struct intel_uncore_extra_reg *er = &box->shared_regs[0]; + + if (uncore_box_is_fake(box) || !reg1->alloc) + return; + + atomic_sub(1 << (reg1->idx * 8), &er->ref); + reg1->alloc = 0; +} + +static int snbep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK; + + if (ev_sel >= 0xb && ev_sel <= 0xe) { + reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER; + reg1->idx = ev_sel - 0xb; + reg1->config = event->attr.config1 & (0xff << reg1->idx); + } + return 0; +} + +static struct intel_uncore_ops snbep_uncore_pcu_ops = { + SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), + .hw_config = snbep_pcu_hw_config, + .get_constraint = snbep_pcu_get_constraint, + .put_constraint = snbep_pcu_put_constraint, +}; + +static struct intel_uncore_type snbep_uncore_pcu = { + .name = "pcu", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .perf_ctr = SNBEP_PCU_MSR_PMON_CTR0, + .event_ctl = SNBEP_PCU_MSR_PMON_CTL0, + .event_mask = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK, + .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL, + .num_shared_regs = 1, + .ops = &snbep_uncore_pcu_ops, + .format_group = &snbep_uncore_pcu_format_group, +}; + +static struct intel_uncore_type *snbep_msr_uncores[] = { + &snbep_uncore_ubox, + &snbep_uncore_cbox, + &snbep_uncore_pcu, + NULL, +}; + +void snbep_uncore_cpu_init(void) +{ + if (snbep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores) + snbep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores; + uncore_msr_uncores = snbep_msr_uncores; +} + +enum { + SNBEP_PCI_QPI_PORT0_FILTER, + SNBEP_PCI_QPI_PORT1_FILTER, +}; + +static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + struct hw_perf_event_extra *reg2 = &hwc->branch_reg; + + if ((hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK) == 0x38) { + reg1->idx = 0; + reg1->reg = SNBEP_Q_Py_PCI_PMON_PKT_MATCH0; + reg1->config = event->attr.config1; + reg2->reg = SNBEP_Q_Py_PCI_PMON_PKT_MASK0; + reg2->config = event->attr.config2; + } + return 0; +} + +static void snbep_qpi_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + struct hw_perf_event_extra *reg2 = &hwc->branch_reg; + + if (reg1->idx != EXTRA_REG_NONE) { + int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER; + struct pci_dev *filter_pdev = uncore_extra_pci_dev[box->phys_id][idx]; + WARN_ON_ONCE(!filter_pdev); + if (filter_pdev) { + pci_write_config_dword(filter_pdev, reg1->reg, + (u32)reg1->config); + pci_write_config_dword(filter_pdev, reg1->reg + 4, + (u32)(reg1->config >> 32)); + pci_write_config_dword(filter_pdev, reg2->reg, + (u32)reg2->config); + pci_write_config_dword(filter_pdev, reg2->reg + 4, + (u32)(reg2->config >> 32)); + } + } + + pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); +} + +static struct intel_uncore_ops snbep_uncore_qpi_ops = { + SNBEP_UNCORE_PCI_OPS_COMMON_INIT(), + .enable_event = snbep_qpi_enable_event, + .hw_config = snbep_qpi_hw_config, + .get_constraint = uncore_get_constraint, + .put_constraint = uncore_put_constraint, +}; + +#define SNBEP_UNCORE_PCI_COMMON_INIT() \ + .perf_ctr = SNBEP_PCI_PMON_CTR0, \ + .event_ctl = SNBEP_PCI_PMON_CTL0, \ + .event_mask = SNBEP_PMON_RAW_EVENT_MASK, \ + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ + .ops = &snbep_uncore_pci_ops, \ + .format_group = &snbep_uncore_format_group + +static struct intel_uncore_type snbep_uncore_ha = { + .name = "ha", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + SNBEP_UNCORE_PCI_COMMON_INIT(), +}; + +static struct intel_uncore_type snbep_uncore_imc = { + .name = "imc", + .num_counters = 4, + .num_boxes = 4, + .perf_ctr_bits = 48, + .fixed_ctr_bits = 48, + .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, + .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, + .event_descs = snbep_uncore_imc_events, + SNBEP_UNCORE_PCI_COMMON_INIT(), +}; + +static struct intel_uncore_type snbep_uncore_qpi = { + .name = "qpi", + .num_counters = 4, + .num_boxes = 2, + .perf_ctr_bits = 48, + .perf_ctr = SNBEP_PCI_PMON_CTR0, + .event_ctl = SNBEP_PCI_PMON_CTL0, + .event_mask = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK, + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, + .num_shared_regs = 1, + .ops = &snbep_uncore_qpi_ops, + .event_descs = snbep_uncore_qpi_events, + .format_group = &snbep_uncore_qpi_format_group, +}; + + +static struct intel_uncore_type snbep_uncore_r2pcie = { + .name = "r2pcie", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 44, + .constraints = snbep_uncore_r2pcie_constraints, + SNBEP_UNCORE_PCI_COMMON_INIT(), +}; + +static struct intel_uncore_type snbep_uncore_r3qpi = { + .name = "r3qpi", + .num_counters = 3, + .num_boxes = 2, + .perf_ctr_bits = 44, + .constraints = snbep_uncore_r3qpi_constraints, + SNBEP_UNCORE_PCI_COMMON_INIT(), +}; + +enum { + SNBEP_PCI_UNCORE_HA, + SNBEP_PCI_UNCORE_IMC, + SNBEP_PCI_UNCORE_QPI, + SNBEP_PCI_UNCORE_R2PCIE, + SNBEP_PCI_UNCORE_R3QPI, +}; + +static struct intel_uncore_type *snbep_pci_uncores[] = { + [SNBEP_PCI_UNCORE_HA] = &snbep_uncore_ha, + [SNBEP_PCI_UNCORE_IMC] = &snbep_uncore_imc, + [SNBEP_PCI_UNCORE_QPI] = &snbep_uncore_qpi, + [SNBEP_PCI_UNCORE_R2PCIE] = &snbep_uncore_r2pcie, + [SNBEP_PCI_UNCORE_R3QPI] = &snbep_uncore_r3qpi, + NULL, +}; + +static DEFINE_PCI_DEVICE_TABLE(snbep_uncore_pci_ids) = { + { /* Home Agent */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA), + .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_HA, 0), + }, + { /* MC Channel 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0), + .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 0), + }, + { /* MC Channel 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1), + .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 1), + }, + { /* MC Channel 2 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2), + .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 2), + }, + { /* MC Channel 3 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3), + .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 3), + }, + { /* QPI Port 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0), + .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 0), + }, + { /* QPI Port 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1), + .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 1), + }, + { /* R2PCIe */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE), + .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R2PCIE, 0), + }, + { /* R3QPI Link 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0), + .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 0), + }, + { /* R3QPI Link 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1), + .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 1), + }, + { /* QPI Port 0 filter */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c86), + .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, + SNBEP_PCI_QPI_PORT0_FILTER), + }, + { /* QPI Port 0 filter */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c96), + .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, + SNBEP_PCI_QPI_PORT1_FILTER), + }, + { /* end: all zeroes */ } +}; + +static struct pci_driver snbep_uncore_pci_driver = { + .name = "snbep_uncore", + .id_table = snbep_uncore_pci_ids, +}; + +/* + * build pci bus to socket mapping + */ +static int snbep_pci2phy_map_init(int devid) +{ + struct pci_dev *ubox_dev = NULL; + int i, bus, nodeid; + int err = 0; + u32 config = 0; + + while (1) { + /* find the UBOX device */ + ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, ubox_dev); + if (!ubox_dev) + break; + bus = ubox_dev->bus->number; + /* get the Node ID of the local register */ + err = pci_read_config_dword(ubox_dev, 0x40, &config); + if (err) + break; + nodeid = config; + /* get the Node ID mapping */ + err = pci_read_config_dword(ubox_dev, 0x54, &config); + if (err) + break; + /* + * every three bits in the Node ID mapping register maps + * to a particular node. + */ + for (i = 0; i < 8; i++) { + if (nodeid == ((config >> (3 * i)) & 0x7)) { + uncore_pcibus_to_physid[bus] = i; + break; + } + } + } + + if (!err) { + /* + * For PCI bus with no UBOX device, find the next bus + * that has UBOX device and use its mapping. + */ + i = -1; + for (bus = 255; bus >= 0; bus--) { + if (uncore_pcibus_to_physid[bus] >= 0) + i = uncore_pcibus_to_physid[bus]; + else + uncore_pcibus_to_physid[bus] = i; + } + } + + if (ubox_dev) + pci_dev_put(ubox_dev); + + return err ? pcibios_err_to_errno(err) : 0; +} + +int snbep_uncore_pci_init(void) +{ + int ret = snbep_pci2phy_map_init(0x3ce0); + if (ret) + return ret; + uncore_pci_uncores = snbep_pci_uncores; + uncore_pci_driver = &snbep_uncore_pci_driver; + return 0; +} +/* end of Sandy Bridge-EP uncore support */ + +/* IvyTown uncore support */ +static void ivt_uncore_msr_init_box(struct intel_uncore_box *box) +{ + unsigned msr = uncore_msr_box_ctl(box); + if (msr) + wrmsrl(msr, IVT_PMON_BOX_CTL_INT); +} + +static void ivt_uncore_pci_init_box(struct intel_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + + pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, IVT_PMON_BOX_CTL_INT); +} + +#define IVT_UNCORE_MSR_OPS_COMMON_INIT() \ + .init_box = ivt_uncore_msr_init_box, \ + .disable_box = snbep_uncore_msr_disable_box, \ + .enable_box = snbep_uncore_msr_enable_box, \ + .disable_event = snbep_uncore_msr_disable_event, \ + .enable_event = snbep_uncore_msr_enable_event, \ + .read_counter = uncore_msr_read_counter + +static struct intel_uncore_ops ivt_uncore_msr_ops = { + IVT_UNCORE_MSR_OPS_COMMON_INIT(), +}; + +static struct intel_uncore_ops ivt_uncore_pci_ops = { + .init_box = ivt_uncore_pci_init_box, + .disable_box = snbep_uncore_pci_disable_box, + .enable_box = snbep_uncore_pci_enable_box, + .disable_event = snbep_uncore_pci_disable_event, + .enable_event = snbep_uncore_pci_enable_event, + .read_counter = snbep_uncore_pci_read_counter, +}; + +#define IVT_UNCORE_PCI_COMMON_INIT() \ + .perf_ctr = SNBEP_PCI_PMON_CTR0, \ + .event_ctl = SNBEP_PCI_PMON_CTL0, \ + .event_mask = IVT_PMON_RAW_EVENT_MASK, \ + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ + .ops = &ivt_uncore_pci_ops, \ + .format_group = &ivt_uncore_format_group + +static struct attribute *ivt_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh8.attr, + NULL, +}; + +static struct attribute *ivt_uncore_ubox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, + NULL, +}; + +static struct attribute *ivt_uncore_cbox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_tid_en.attr, + &format_attr_thresh8.attr, + &format_attr_filter_tid.attr, + &format_attr_filter_link.attr, + &format_attr_filter_state2.attr, + &format_attr_filter_nid2.attr, + &format_attr_filter_opc2.attr, + NULL, +}; + +static struct attribute *ivt_uncore_pcu_formats_attr[] = { + &format_attr_event_ext.attr, + &format_attr_occ_sel.attr, + &format_attr_edge.attr, + &format_attr_thresh5.attr, + &format_attr_occ_invert.attr, + &format_attr_occ_edge.attr, + &format_attr_filter_band0.attr, + &format_attr_filter_band1.attr, + &format_attr_filter_band2.attr, + &format_attr_filter_band3.attr, + NULL, +}; + +static struct attribute *ivt_uncore_qpi_formats_attr[] = { + &format_attr_event_ext.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_thresh8.attr, + &format_attr_match_rds.attr, + &format_attr_match_rnid30.attr, + &format_attr_match_rnid4.attr, + &format_attr_match_dnid.attr, + &format_attr_match_mc.attr, + &format_attr_match_opc.attr, + &format_attr_match_vnw.attr, + &format_attr_match0.attr, + &format_attr_match1.attr, + &format_attr_mask_rds.attr, + &format_attr_mask_rnid30.attr, + &format_attr_mask_rnid4.attr, + &format_attr_mask_dnid.attr, + &format_attr_mask_mc.attr, + &format_attr_mask_opc.attr, + &format_attr_mask_vnw.attr, + &format_attr_mask0.attr, + &format_attr_mask1.attr, + NULL, +}; + +static struct attribute_group ivt_uncore_format_group = { + .name = "format", + .attrs = ivt_uncore_formats_attr, +}; + +static struct attribute_group ivt_uncore_ubox_format_group = { + .name = "format", + .attrs = ivt_uncore_ubox_formats_attr, +}; + +static struct attribute_group ivt_uncore_cbox_format_group = { + .name = "format", + .attrs = ivt_uncore_cbox_formats_attr, +}; + +static struct attribute_group ivt_uncore_pcu_format_group = { + .name = "format", + .attrs = ivt_uncore_pcu_formats_attr, +}; + +static struct attribute_group ivt_uncore_qpi_format_group = { + .name = "format", + .attrs = ivt_uncore_qpi_formats_attr, +}; + +static struct intel_uncore_type ivt_uncore_ubox = { + .name = "ubox", + .num_counters = 2, + .num_boxes = 1, + .perf_ctr_bits = 44, + .fixed_ctr_bits = 48, + .perf_ctr = SNBEP_U_MSR_PMON_CTR0, + .event_ctl = SNBEP_U_MSR_PMON_CTL0, + .event_mask = IVT_U_MSR_PMON_RAW_EVENT_MASK, + .fixed_ctr = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR, + .fixed_ctl = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL, + .ops = &ivt_uncore_msr_ops, + .format_group = &ivt_uncore_ubox_format_group, +}; + +static struct extra_reg ivt_uncore_cbox_extra_regs[] = { + SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN, + SNBEP_CBO_PMON_CTL_TID_EN, 0x1), + SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2), + SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4), + SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc), + SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc), + SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4), + SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc), + SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4), + SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc), + SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4), + SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc), + SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18), + SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18), + SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x2136, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18), + SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18), + SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8), + SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10), + SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8), + EVENT_EXTRA_END +}; + +static u64 ivt_cbox_filter_mask(int fields) +{ + u64 mask = 0; + + if (fields & 0x1) + mask |= IVT_CB0_MSR_PMON_BOX_FILTER_TID; + if (fields & 0x2) + mask |= IVT_CB0_MSR_PMON_BOX_FILTER_LINK; + if (fields & 0x4) + mask |= IVT_CB0_MSR_PMON_BOX_FILTER_STATE; + if (fields & 0x8) + mask |= IVT_CB0_MSR_PMON_BOX_FILTER_NID; + if (fields & 0x10) + mask |= IVT_CB0_MSR_PMON_BOX_FILTER_OPC; + + return mask; +} + +static struct event_constraint * +ivt_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) +{ + return __snbep_cbox_get_constraint(box, event, ivt_cbox_filter_mask); +} + +static int ivt_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + struct extra_reg *er; + int idx = 0; + + for (er = ivt_uncore_cbox_extra_regs; er->msr; er++) { + if (er->event != (event->hw.config & er->config_mask)) + continue; + idx |= er->idx; + } + + if (idx) { + reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER + + SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx; + reg1->config = event->attr.config1 & ivt_cbox_filter_mask(idx); + reg1->idx = idx; + } + return 0; +} + +static void ivt_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + + if (reg1->idx != EXTRA_REG_NONE) { + u64 filter = uncore_shared_reg_config(box, 0); + wrmsrl(reg1->reg, filter & 0xffffffff); + wrmsrl(reg1->reg + 6, filter >> 32); + } + + wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); +} + +static struct intel_uncore_ops ivt_uncore_cbox_ops = { + .init_box = ivt_uncore_msr_init_box, + .disable_box = snbep_uncore_msr_disable_box, + .enable_box = snbep_uncore_msr_enable_box, + .disable_event = snbep_uncore_msr_disable_event, + .enable_event = ivt_cbox_enable_event, + .read_counter = uncore_msr_read_counter, + .hw_config = ivt_cbox_hw_config, + .get_constraint = ivt_cbox_get_constraint, + .put_constraint = snbep_cbox_put_constraint, +}; + +static struct intel_uncore_type ivt_uncore_cbox = { + .name = "cbox", + .num_counters = 4, + .num_boxes = 15, + .perf_ctr_bits = 44, + .event_ctl = SNBEP_C0_MSR_PMON_CTL0, + .perf_ctr = SNBEP_C0_MSR_PMON_CTR0, + .event_mask = IVT_CBO_MSR_PMON_RAW_EVENT_MASK, + .box_ctl = SNBEP_C0_MSR_PMON_BOX_CTL, + .msr_offset = SNBEP_CBO_MSR_OFFSET, + .num_shared_regs = 1, + .constraints = snbep_uncore_cbox_constraints, + .ops = &ivt_uncore_cbox_ops, + .format_group = &ivt_uncore_cbox_format_group, +}; + +static struct intel_uncore_ops ivt_uncore_pcu_ops = { + IVT_UNCORE_MSR_OPS_COMMON_INIT(), + .hw_config = snbep_pcu_hw_config, + .get_constraint = snbep_pcu_get_constraint, + .put_constraint = snbep_pcu_put_constraint, +}; + +static struct intel_uncore_type ivt_uncore_pcu = { + .name = "pcu", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .perf_ctr = SNBEP_PCU_MSR_PMON_CTR0, + .event_ctl = SNBEP_PCU_MSR_PMON_CTL0, + .event_mask = IVT_PCU_MSR_PMON_RAW_EVENT_MASK, + .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL, + .num_shared_regs = 1, + .ops = &ivt_uncore_pcu_ops, + .format_group = &ivt_uncore_pcu_format_group, +}; + +static struct intel_uncore_type *ivt_msr_uncores[] = { + &ivt_uncore_ubox, + &ivt_uncore_cbox, + &ivt_uncore_pcu, + NULL, +}; + +void ivt_uncore_cpu_init(void) +{ + if (ivt_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores) + ivt_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores; + uncore_msr_uncores = ivt_msr_uncores; +} + +static struct intel_uncore_type ivt_uncore_ha = { + .name = "ha", + .num_counters = 4, + .num_boxes = 2, + .perf_ctr_bits = 48, + IVT_UNCORE_PCI_COMMON_INIT(), +}; + +static struct intel_uncore_type ivt_uncore_imc = { + .name = "imc", + .num_counters = 4, + .num_boxes = 8, + .perf_ctr_bits = 48, + .fixed_ctr_bits = 48, + .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, + .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, + IVT_UNCORE_PCI_COMMON_INIT(), +}; + +/* registers in IRP boxes are not properly aligned */ +static unsigned ivt_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4}; +static unsigned ivt_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0}; + +static void ivt_uncore_irp_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + + pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx], + hwc->config | SNBEP_PMON_CTL_EN); +} + +static void ivt_uncore_irp_disable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + + pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx], hwc->config); +} + +static u64 ivt_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + u64 count = 0; + + pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx], (u32 *)&count); + pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1); + + return count; +} + +static struct intel_uncore_ops ivt_uncore_irp_ops = { + .init_box = ivt_uncore_pci_init_box, + .disable_box = snbep_uncore_pci_disable_box, + .enable_box = snbep_uncore_pci_enable_box, + .disable_event = ivt_uncore_irp_disable_event, + .enable_event = ivt_uncore_irp_enable_event, + .read_counter = ivt_uncore_irp_read_counter, +}; + +static struct intel_uncore_type ivt_uncore_irp = { + .name = "irp", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .event_mask = IVT_PMON_RAW_EVENT_MASK, + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, + .ops = &ivt_uncore_irp_ops, + .format_group = &ivt_uncore_format_group, +}; + +static struct intel_uncore_ops ivt_uncore_qpi_ops = { + .init_box = ivt_uncore_pci_init_box, + .disable_box = snbep_uncore_pci_disable_box, + .enable_box = snbep_uncore_pci_enable_box, + .disable_event = snbep_uncore_pci_disable_event, + .enable_event = snbep_qpi_enable_event, + .read_counter = snbep_uncore_pci_read_counter, + .hw_config = snbep_qpi_hw_config, + .get_constraint = uncore_get_constraint, + .put_constraint = uncore_put_constraint, +}; + +static struct intel_uncore_type ivt_uncore_qpi = { + .name = "qpi", + .num_counters = 4, + .num_boxes = 3, + .perf_ctr_bits = 48, + .perf_ctr = SNBEP_PCI_PMON_CTR0, + .event_ctl = SNBEP_PCI_PMON_CTL0, + .event_mask = IVT_QPI_PCI_PMON_RAW_EVENT_MASK, + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, + .num_shared_regs = 1, + .ops = &ivt_uncore_qpi_ops, + .format_group = &ivt_uncore_qpi_format_group, +}; + +static struct intel_uncore_type ivt_uncore_r2pcie = { + .name = "r2pcie", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 44, + .constraints = snbep_uncore_r2pcie_constraints, + IVT_UNCORE_PCI_COMMON_INIT(), +}; + +static struct intel_uncore_type ivt_uncore_r3qpi = { + .name = "r3qpi", + .num_counters = 3, + .num_boxes = 2, + .perf_ctr_bits = 44, + .constraints = snbep_uncore_r3qpi_constraints, + IVT_UNCORE_PCI_COMMON_INIT(), +}; + +enum { + IVT_PCI_UNCORE_HA, + IVT_PCI_UNCORE_IMC, + IVT_PCI_UNCORE_IRP, + IVT_PCI_UNCORE_QPI, + IVT_PCI_UNCORE_R2PCIE, + IVT_PCI_UNCORE_R3QPI, +}; + +static struct intel_uncore_type *ivt_pci_uncores[] = { + [IVT_PCI_UNCORE_HA] = &ivt_uncore_ha, + [IVT_PCI_UNCORE_IMC] = &ivt_uncore_imc, + [IVT_PCI_UNCORE_IRP] = &ivt_uncore_irp, + [IVT_PCI_UNCORE_QPI] = &ivt_uncore_qpi, + [IVT_PCI_UNCORE_R2PCIE] = &ivt_uncore_r2pcie, + [IVT_PCI_UNCORE_R3QPI] = &ivt_uncore_r3qpi, + NULL, +}; + +static DEFINE_PCI_DEVICE_TABLE(ivt_uncore_pci_ids) = { + { /* Home Agent 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 0), + }, + { /* Home Agent 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 1), + }, + { /* MC0 Channel 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 0), + }, + { /* MC0 Channel 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 1), + }, + { /* MC0 Channel 3 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 2), + }, + { /* MC0 Channel 4 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 3), + }, + { /* MC1 Channel 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 4), + }, + { /* MC1 Channel 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 5), + }, + { /* MC1 Channel 3 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 6), + }, + { /* MC1 Channel 4 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 7), + }, + { /* IRP */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe39), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IRP, 0), + }, + { /* QPI0 Port 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 0), + }, + { /* QPI0 Port 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 1), + }, + { /* QPI1 Port 2 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 2), + }, + { /* R2PCIe */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R2PCIE, 0), + }, + { /* R3QPI0 Link 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 0), + }, + { /* R3QPI0 Link 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 1), + }, + { /* R3QPI1 Link 2 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e), + .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 2), + }, + { /* QPI Port 0 filter */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe86), + .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, + SNBEP_PCI_QPI_PORT0_FILTER), + }, + { /* QPI Port 0 filter */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe96), + .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, + SNBEP_PCI_QPI_PORT1_FILTER), + }, + { /* end: all zeroes */ } +}; + +static struct pci_driver ivt_uncore_pci_driver = { + .name = "ivt_uncore", + .id_table = ivt_uncore_pci_ids, +}; + +int ivt_uncore_pci_init(void) +{ + int ret = snbep_pci2phy_map_init(0x0e1e); + if (ret) + return ret; + uncore_pci_uncores = ivt_pci_uncores; + uncore_pci_driver = &ivt_uncore_pci_driver; + return 0; +} +/* end of IvyTown uncore support */ -- GitLab From c1e46580c3b7bf25053519cf39f01a2f9ea4d865 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 30 Jul 2014 15:22:15 +0800 Subject: [PATCH 0198/5088] perf/x86/uncore: move NHM-EX/WSM-EX specific code to seperate file Signed-off-by: Yan, Zheng Signed-off-by: Peter Zijlstra Cc: Andi Kleen Cc: Arnaldo Carvalho de Melo Cc: Borislav Petkov Cc: Paul Mackerras Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406704935-27708-4-git-send-email-zheng.z.yan@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/Makefile | 2 +- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 1038 +------------- arch/x86/kernel/cpu/perf_event_intel_uncore.h | 185 +-- .../cpu/perf_event_intel_uncore_nhmex.c | 1221 +++++++++++++++++ 4 files changed, 1227 insertions(+), 1219 deletions(-) create mode 100644 arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 7dee8664573a..7e1fd4e08552 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -37,7 +37,7 @@ endif obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o perf_event_intel_uncore_snb.o -obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore_snbep.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore_snbep.o perf_event_intel_uncore_nhmex.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_rapl.o endif diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index cf6966a37580..b1f84d9ccc48 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -28,15 +28,6 @@ ssize_t uncore_event_show(struct kobject *kobj, return sprintf(buf, "%s", event->config); } -#define __BITS_VALUE(x, i, n) ((typeof(x))(((x) >> ((i) * (n))) & \ - ((1ULL << (n)) - 1))) - -DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); -DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); -DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); -DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); -DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31"); - struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event) { return container_of(event->pmu, struct intel_uncore_pmu, pmu); @@ -158,1025 +149,6 @@ u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx) return config; } -/* Nehalem-EX uncore support */ -DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5"); -DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7"); -DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63"); -DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63"); - -static void nhmex_uncore_msr_init_box(struct intel_uncore_box *box) -{ - wrmsrl(NHMEX_U_MSR_PMON_GLOBAL_CTL, NHMEX_U_PMON_GLOBAL_EN_ALL); -} - -static void nhmex_uncore_msr_disable_box(struct intel_uncore_box *box) -{ - unsigned msr = uncore_msr_box_ctl(box); - u64 config; - - if (msr) { - rdmsrl(msr, config); - config &= ~((1ULL << uncore_num_counters(box)) - 1); - /* WBox has a fixed counter */ - if (uncore_msr_fixed_ctl(box)) - config &= ~NHMEX_W_PMON_GLOBAL_FIXED_EN; - wrmsrl(msr, config); - } -} - -static void nhmex_uncore_msr_enable_box(struct intel_uncore_box *box) -{ - unsigned msr = uncore_msr_box_ctl(box); - u64 config; - - if (msr) { - rdmsrl(msr, config); - config |= (1ULL << uncore_num_counters(box)) - 1; - /* WBox has a fixed counter */ - if (uncore_msr_fixed_ctl(box)) - config |= NHMEX_W_PMON_GLOBAL_FIXED_EN; - wrmsrl(msr, config); - } -} - -static void nhmex_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - wrmsrl(event->hw.config_base, 0); -} - -static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - - if (hwc->idx >= UNCORE_PMC_IDX_FIXED) - wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0); - else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0) - wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22); - else - wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0); -} - -#define NHMEX_UNCORE_OPS_COMMON_INIT() \ - .init_box = nhmex_uncore_msr_init_box, \ - .disable_box = nhmex_uncore_msr_disable_box, \ - .enable_box = nhmex_uncore_msr_enable_box, \ - .disable_event = nhmex_uncore_msr_disable_event, \ - .read_counter = uncore_msr_read_counter - -static struct intel_uncore_ops nhmex_uncore_ops = { - NHMEX_UNCORE_OPS_COMMON_INIT(), - .enable_event = nhmex_uncore_msr_enable_event, -}; - -static struct attribute *nhmex_uncore_ubox_formats_attr[] = { - &format_attr_event.attr, - &format_attr_edge.attr, - NULL, -}; - -static struct attribute_group nhmex_uncore_ubox_format_group = { - .name = "format", - .attrs = nhmex_uncore_ubox_formats_attr, -}; - -static struct intel_uncore_type nhmex_uncore_ubox = { - .name = "ubox", - .num_counters = 1, - .num_boxes = 1, - .perf_ctr_bits = 48, - .event_ctl = NHMEX_U_MSR_PMON_EV_SEL, - .perf_ctr = NHMEX_U_MSR_PMON_CTR, - .event_mask = NHMEX_U_PMON_RAW_EVENT_MASK, - .box_ctl = NHMEX_U_MSR_PMON_GLOBAL_CTL, - .ops = &nhmex_uncore_ops, - .format_group = &nhmex_uncore_ubox_format_group -}; - -static struct attribute *nhmex_uncore_cbox_formats_attr[] = { - &format_attr_event.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_inv.attr, - &format_attr_thresh8.attr, - NULL, -}; - -static struct attribute_group nhmex_uncore_cbox_format_group = { - .name = "format", - .attrs = nhmex_uncore_cbox_formats_attr, -}; - -/* msr offset for each instance of cbox */ -static unsigned nhmex_cbox_msr_offsets[] = { - 0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0, -}; - -static struct intel_uncore_type nhmex_uncore_cbox = { - .name = "cbox", - .num_counters = 6, - .num_boxes = 10, - .perf_ctr_bits = 48, - .event_ctl = NHMEX_C0_MSR_PMON_EV_SEL0, - .perf_ctr = NHMEX_C0_MSR_PMON_CTR0, - .event_mask = NHMEX_PMON_RAW_EVENT_MASK, - .box_ctl = NHMEX_C0_MSR_PMON_GLOBAL_CTL, - .msr_offsets = nhmex_cbox_msr_offsets, - .pair_ctr_ctl = 1, - .ops = &nhmex_uncore_ops, - .format_group = &nhmex_uncore_cbox_format_group -}; - -static struct uncore_event_desc nhmex_uncore_wbox_events[] = { - INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0"), - { /* end: all zeroes */ }, -}; - -static struct intel_uncore_type nhmex_uncore_wbox = { - .name = "wbox", - .num_counters = 4, - .num_boxes = 1, - .perf_ctr_bits = 48, - .event_ctl = NHMEX_W_MSR_PMON_CNT0, - .perf_ctr = NHMEX_W_MSR_PMON_EVT_SEL0, - .fixed_ctr = NHMEX_W_MSR_PMON_FIXED_CTR, - .fixed_ctl = NHMEX_W_MSR_PMON_FIXED_CTL, - .event_mask = NHMEX_PMON_RAW_EVENT_MASK, - .box_ctl = NHMEX_W_MSR_GLOBAL_CTL, - .pair_ctr_ctl = 1, - .event_descs = nhmex_uncore_wbox_events, - .ops = &nhmex_uncore_ops, - .format_group = &nhmex_uncore_cbox_format_group -}; - -static int nhmex_bbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - struct hw_perf_event_extra *reg2 = &hwc->branch_reg; - int ctr, ev_sel; - - ctr = (hwc->config & NHMEX_B_PMON_CTR_MASK) >> - NHMEX_B_PMON_CTR_SHIFT; - ev_sel = (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK) >> - NHMEX_B_PMON_CTL_EV_SEL_SHIFT; - - /* events that do not use the match/mask registers */ - if ((ctr == 0 && ev_sel > 0x3) || (ctr == 1 && ev_sel > 0x6) || - (ctr == 2 && ev_sel != 0x4) || ctr == 3) - return 0; - - if (box->pmu->pmu_idx == 0) - reg1->reg = NHMEX_B0_MSR_MATCH; - else - reg1->reg = NHMEX_B1_MSR_MATCH; - reg1->idx = 0; - reg1->config = event->attr.config1; - reg2->config = event->attr.config2; - return 0; -} - -static void nhmex_bbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - struct hw_perf_event_extra *reg2 = &hwc->branch_reg; - - if (reg1->idx != EXTRA_REG_NONE) { - wrmsrl(reg1->reg, reg1->config); - wrmsrl(reg1->reg + 1, reg2->config); - } - wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 | - (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK)); -} - -/* - * The Bbox has 4 counters, but each counter monitors different events. - * Use bits 6-7 in the event config to select counter. - */ -static struct event_constraint nhmex_uncore_bbox_constraints[] = { - EVENT_CONSTRAINT(0 , 1, 0xc0), - EVENT_CONSTRAINT(0x40, 2, 0xc0), - EVENT_CONSTRAINT(0x80, 4, 0xc0), - EVENT_CONSTRAINT(0xc0, 8, 0xc0), - EVENT_CONSTRAINT_END, -}; - -static struct attribute *nhmex_uncore_bbox_formats_attr[] = { - &format_attr_event5.attr, - &format_attr_counter.attr, - &format_attr_match.attr, - &format_attr_mask.attr, - NULL, -}; - -static struct attribute_group nhmex_uncore_bbox_format_group = { - .name = "format", - .attrs = nhmex_uncore_bbox_formats_attr, -}; - -static struct intel_uncore_ops nhmex_uncore_bbox_ops = { - NHMEX_UNCORE_OPS_COMMON_INIT(), - .enable_event = nhmex_bbox_msr_enable_event, - .hw_config = nhmex_bbox_hw_config, - .get_constraint = uncore_get_constraint, - .put_constraint = uncore_put_constraint, -}; - -static struct intel_uncore_type nhmex_uncore_bbox = { - .name = "bbox", - .num_counters = 4, - .num_boxes = 2, - .perf_ctr_bits = 48, - .event_ctl = NHMEX_B0_MSR_PMON_CTL0, - .perf_ctr = NHMEX_B0_MSR_PMON_CTR0, - .event_mask = NHMEX_B_PMON_RAW_EVENT_MASK, - .box_ctl = NHMEX_B0_MSR_PMON_GLOBAL_CTL, - .msr_offset = NHMEX_B_MSR_OFFSET, - .pair_ctr_ctl = 1, - .num_shared_regs = 1, - .constraints = nhmex_uncore_bbox_constraints, - .ops = &nhmex_uncore_bbox_ops, - .format_group = &nhmex_uncore_bbox_format_group -}; - -static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - struct hw_perf_event_extra *reg2 = &hwc->branch_reg; - - /* only TO_R_PROG_EV event uses the match/mask register */ - if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) != - NHMEX_S_EVENT_TO_R_PROG_EV) - return 0; - - if (box->pmu->pmu_idx == 0) - reg1->reg = NHMEX_S0_MSR_MM_CFG; - else - reg1->reg = NHMEX_S1_MSR_MM_CFG; - reg1->idx = 0; - reg1->config = event->attr.config1; - reg2->config = event->attr.config2; - return 0; -} - -static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - struct hw_perf_event_extra *reg2 = &hwc->branch_reg; - - if (reg1->idx != EXTRA_REG_NONE) { - wrmsrl(reg1->reg, 0); - wrmsrl(reg1->reg + 1, reg1->config); - wrmsrl(reg1->reg + 2, reg2->config); - wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN); - } - wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22); -} - -static struct attribute *nhmex_uncore_sbox_formats_attr[] = { - &format_attr_event.attr, - &format_attr_umask.attr, - &format_attr_edge.attr, - &format_attr_inv.attr, - &format_attr_thresh8.attr, - &format_attr_match.attr, - &format_attr_mask.attr, - NULL, -}; - -static struct attribute_group nhmex_uncore_sbox_format_group = { - .name = "format", - .attrs = nhmex_uncore_sbox_formats_attr, -}; - -static struct intel_uncore_ops nhmex_uncore_sbox_ops = { - NHMEX_UNCORE_OPS_COMMON_INIT(), - .enable_event = nhmex_sbox_msr_enable_event, - .hw_config = nhmex_sbox_hw_config, - .get_constraint = uncore_get_constraint, - .put_constraint = uncore_put_constraint, -}; - -static struct intel_uncore_type nhmex_uncore_sbox = { - .name = "sbox", - .num_counters = 4, - .num_boxes = 2, - .perf_ctr_bits = 48, - .event_ctl = NHMEX_S0_MSR_PMON_CTL0, - .perf_ctr = NHMEX_S0_MSR_PMON_CTR0, - .event_mask = NHMEX_PMON_RAW_EVENT_MASK, - .box_ctl = NHMEX_S0_MSR_PMON_GLOBAL_CTL, - .msr_offset = NHMEX_S_MSR_OFFSET, - .pair_ctr_ctl = 1, - .num_shared_regs = 1, - .ops = &nhmex_uncore_sbox_ops, - .format_group = &nhmex_uncore_sbox_format_group -}; - -enum { - EXTRA_REG_NHMEX_M_FILTER, - EXTRA_REG_NHMEX_M_DSP, - EXTRA_REG_NHMEX_M_ISS, - EXTRA_REG_NHMEX_M_MAP, - EXTRA_REG_NHMEX_M_MSC_THR, - EXTRA_REG_NHMEX_M_PGT, - EXTRA_REG_NHMEX_M_PLD, - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC, -}; - -static struct extra_reg nhmex_uncore_mbox_extra_regs[] = { - MBOX_INC_SEL_EXTAR_REG(0x0, DSP), - MBOX_INC_SEL_EXTAR_REG(0x4, MSC_THR), - MBOX_INC_SEL_EXTAR_REG(0x5, MSC_THR), - MBOX_INC_SEL_EXTAR_REG(0x9, ISS), - /* event 0xa uses two extra registers */ - MBOX_INC_SEL_EXTAR_REG(0xa, ISS), - MBOX_INC_SEL_EXTAR_REG(0xa, PLD), - MBOX_INC_SEL_EXTAR_REG(0xb, PLD), - /* events 0xd ~ 0x10 use the same extra register */ - MBOX_INC_SEL_EXTAR_REG(0xd, ZDP_CTL_FVC), - MBOX_INC_SEL_EXTAR_REG(0xe, ZDP_CTL_FVC), - MBOX_INC_SEL_EXTAR_REG(0xf, ZDP_CTL_FVC), - MBOX_INC_SEL_EXTAR_REG(0x10, ZDP_CTL_FVC), - MBOX_INC_SEL_EXTAR_REG(0x16, PGT), - MBOX_SET_FLAG_SEL_EXTRA_REG(0x0, DSP), - MBOX_SET_FLAG_SEL_EXTRA_REG(0x1, ISS), - MBOX_SET_FLAG_SEL_EXTRA_REG(0x5, PGT), - MBOX_SET_FLAG_SEL_EXTRA_REG(0x6, MAP), - EVENT_EXTRA_END -}; - -/* Nehalem-EX or Westmere-EX ? */ -static bool uncore_nhmex; - -static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config) -{ - struct intel_uncore_extra_reg *er; - unsigned long flags; - bool ret = false; - u64 mask; - - if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) { - er = &box->shared_regs[idx]; - raw_spin_lock_irqsave(&er->lock, flags); - if (!atomic_read(&er->ref) || er->config == config) { - atomic_inc(&er->ref); - er->config = config; - ret = true; - } - raw_spin_unlock_irqrestore(&er->lock, flags); - - return ret; - } - /* - * The ZDP_CTL_FVC MSR has 4 fields which are used to control - * events 0xd ~ 0x10. Besides these 4 fields, there are additional - * fields which are shared. - */ - idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC; - if (WARN_ON_ONCE(idx >= 4)) - return false; - - /* mask of the shared fields */ - if (uncore_nhmex) - mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK; - else - mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK; - er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC]; - - raw_spin_lock_irqsave(&er->lock, flags); - /* add mask of the non-shared field if it's in use */ - if (__BITS_VALUE(atomic_read(&er->ref), idx, 8)) { - if (uncore_nhmex) - mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); - else - mask |= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); - } - - if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) { - atomic_add(1 << (idx * 8), &er->ref); - if (uncore_nhmex) - mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK | - NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); - else - mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK | - WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); - er->config &= ~mask; - er->config |= (config & mask); - ret = true; - } - raw_spin_unlock_irqrestore(&er->lock, flags); - - return ret; -} - -static void nhmex_mbox_put_shared_reg(struct intel_uncore_box *box, int idx) -{ - struct intel_uncore_extra_reg *er; - - if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) { - er = &box->shared_regs[idx]; - atomic_dec(&er->ref); - return; - } - - idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC; - er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC]; - atomic_sub(1 << (idx * 8), &er->ref); -} - -static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - u64 idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8); - u64 config = reg1->config; - - /* get the non-shared control bits and shift them */ - idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC; - if (uncore_nhmex) - config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); - else - config &= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); - if (new_idx > orig_idx) { - idx = new_idx - orig_idx; - config <<= 3 * idx; - } else { - idx = orig_idx - new_idx; - config >>= 3 * idx; - } - - /* add the shared control bits back */ - if (uncore_nhmex) - config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config; - else - config |= WSMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config; - config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config; - if (modify) { - /* adjust the main event selector */ - if (new_idx > orig_idx) - hwc->config += idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT; - else - hwc->config -= idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT; - reg1->config = config; - reg1->idx = ~0xff | new_idx; - } - return config; -} - -static struct event_constraint * -nhmex_mbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - struct hw_perf_event_extra *reg2 = &event->hw.branch_reg; - int i, idx[2], alloc = 0; - u64 config1 = reg1->config; - - idx[0] = __BITS_VALUE(reg1->idx, 0, 8); - idx[1] = __BITS_VALUE(reg1->idx, 1, 8); -again: - for (i = 0; i < 2; i++) { - if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i))) - idx[i] = 0xff; - - if (idx[i] == 0xff) - continue; - - if (!nhmex_mbox_get_shared_reg(box, idx[i], - __BITS_VALUE(config1, i, 32))) - goto fail; - alloc |= (0x1 << i); - } - - /* for the match/mask registers */ - if (reg2->idx != EXTRA_REG_NONE && - (uncore_box_is_fake(box) || !reg2->alloc) && - !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config)) - goto fail; - - /* - * If it's a fake box -- as per validate_{group,event}() we - * shouldn't touch event state and we can avoid doing so - * since both will only call get_event_constraints() once - * on each event, this avoids the need for reg->alloc. - */ - if (!uncore_box_is_fake(box)) { - if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) - nhmex_mbox_alter_er(event, idx[0], true); - reg1->alloc |= alloc; - if (reg2->idx != EXTRA_REG_NONE) - reg2->alloc = 1; - } - return NULL; -fail: - if (idx[0] != 0xff && !(alloc & 0x1) && - idx[0] >= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) { - /* - * events 0xd ~ 0x10 are functional identical, but are - * controlled by different fields in the ZDP_CTL_FVC - * register. If we failed to take one field, try the - * rest 3 choices. - */ - BUG_ON(__BITS_VALUE(reg1->idx, 1, 8) != 0xff); - idx[0] -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC; - idx[0] = (idx[0] + 1) % 4; - idx[0] += EXTRA_REG_NHMEX_M_ZDP_CTL_FVC; - if (idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) { - config1 = nhmex_mbox_alter_er(event, idx[0], false); - goto again; - } - } - - if (alloc & 0x1) - nhmex_mbox_put_shared_reg(box, idx[0]); - if (alloc & 0x2) - nhmex_mbox_put_shared_reg(box, idx[1]); - return &uncore_constraint_empty; -} - -static void nhmex_mbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - struct hw_perf_event_extra *reg2 = &event->hw.branch_reg; - - if (uncore_box_is_fake(box)) - return; - - if (reg1->alloc & 0x1) - nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 0, 8)); - if (reg1->alloc & 0x2) - nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 1, 8)); - reg1->alloc = 0; - - if (reg2->alloc) { - nhmex_mbox_put_shared_reg(box, reg2->idx); - reg2->alloc = 0; - } -} - -static int nhmex_mbox_extra_reg_idx(struct extra_reg *er) -{ - if (er->idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) - return er->idx; - return er->idx + (er->event >> NHMEX_M_PMON_CTL_INC_SEL_SHIFT) - 0xd; -} - -static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) -{ - struct intel_uncore_type *type = box->pmu->type; - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - struct hw_perf_event_extra *reg2 = &event->hw.branch_reg; - struct extra_reg *er; - unsigned msr; - int reg_idx = 0; - /* - * The mbox events may require 2 extra MSRs at the most. But only - * the lower 32 bits in these MSRs are significant, so we can use - * config1 to pass two MSRs' config. - */ - for (er = nhmex_uncore_mbox_extra_regs; er->msr; er++) { - if (er->event != (event->hw.config & er->config_mask)) - continue; - if (event->attr.config1 & ~er->valid_mask) - return -EINVAL; - - msr = er->msr + type->msr_offset * box->pmu->pmu_idx; - if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff)) - return -EINVAL; - - /* always use the 32~63 bits to pass the PLD config */ - if (er->idx == EXTRA_REG_NHMEX_M_PLD) - reg_idx = 1; - else if (WARN_ON_ONCE(reg_idx > 0)) - return -EINVAL; - - reg1->idx &= ~(0xff << (reg_idx * 8)); - reg1->reg &= ~(0xffff << (reg_idx * 16)); - reg1->idx |= nhmex_mbox_extra_reg_idx(er) << (reg_idx * 8); - reg1->reg |= msr << (reg_idx * 16); - reg1->config = event->attr.config1; - reg_idx++; - } - /* - * The mbox only provides ability to perform address matching - * for the PLD events. - */ - if (reg_idx == 2) { - reg2->idx = EXTRA_REG_NHMEX_M_FILTER; - if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN) - reg2->config = event->attr.config2; - else - reg2->config = ~0ULL; - if (box->pmu->pmu_idx == 0) - reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG; - else - reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG; - } - return 0; -} - -static u64 nhmex_mbox_shared_reg_config(struct intel_uncore_box *box, int idx) -{ - struct intel_uncore_extra_reg *er; - unsigned long flags; - u64 config; - - if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) - return box->shared_regs[idx].config; - - er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC]; - raw_spin_lock_irqsave(&er->lock, flags); - config = er->config; - raw_spin_unlock_irqrestore(&er->lock, flags); - return config; -} - -static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - struct hw_perf_event_extra *reg2 = &hwc->branch_reg; - int idx; - - idx = __BITS_VALUE(reg1->idx, 0, 8); - if (idx != 0xff) - wrmsrl(__BITS_VALUE(reg1->reg, 0, 16), - nhmex_mbox_shared_reg_config(box, idx)); - idx = __BITS_VALUE(reg1->idx, 1, 8); - if (idx != 0xff) - wrmsrl(__BITS_VALUE(reg1->reg, 1, 16), - nhmex_mbox_shared_reg_config(box, idx)); - - if (reg2->idx != EXTRA_REG_NONE) { - wrmsrl(reg2->reg, 0); - if (reg2->config != ~0ULL) { - wrmsrl(reg2->reg + 1, - reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK); - wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK & - (reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT)); - wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN); - } - } - - wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0); -} - -DEFINE_UNCORE_FORMAT_ATTR(count_mode, count_mode, "config:2-3"); -DEFINE_UNCORE_FORMAT_ATTR(storage_mode, storage_mode, "config:4-5"); -DEFINE_UNCORE_FORMAT_ATTR(wrap_mode, wrap_mode, "config:6"); -DEFINE_UNCORE_FORMAT_ATTR(flag_mode, flag_mode, "config:7"); -DEFINE_UNCORE_FORMAT_ATTR(inc_sel, inc_sel, "config:9-13"); -DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel, set_flag_sel, "config:19-21"); -DEFINE_UNCORE_FORMAT_ATTR(filter_cfg_en, filter_cfg_en, "config2:63"); -DEFINE_UNCORE_FORMAT_ATTR(filter_match, filter_match, "config2:0-33"); -DEFINE_UNCORE_FORMAT_ATTR(filter_mask, filter_mask, "config2:34-61"); -DEFINE_UNCORE_FORMAT_ATTR(dsp, dsp, "config1:0-31"); -DEFINE_UNCORE_FORMAT_ATTR(thr, thr, "config1:0-31"); -DEFINE_UNCORE_FORMAT_ATTR(fvc, fvc, "config1:0-31"); -DEFINE_UNCORE_FORMAT_ATTR(pgt, pgt, "config1:0-31"); -DEFINE_UNCORE_FORMAT_ATTR(map, map, "config1:0-31"); -DEFINE_UNCORE_FORMAT_ATTR(iss, iss, "config1:0-31"); -DEFINE_UNCORE_FORMAT_ATTR(pld, pld, "config1:32-63"); - -static struct attribute *nhmex_uncore_mbox_formats_attr[] = { - &format_attr_count_mode.attr, - &format_attr_storage_mode.attr, - &format_attr_wrap_mode.attr, - &format_attr_flag_mode.attr, - &format_attr_inc_sel.attr, - &format_attr_set_flag_sel.attr, - &format_attr_filter_cfg_en.attr, - &format_attr_filter_match.attr, - &format_attr_filter_mask.attr, - &format_attr_dsp.attr, - &format_attr_thr.attr, - &format_attr_fvc.attr, - &format_attr_pgt.attr, - &format_attr_map.attr, - &format_attr_iss.attr, - &format_attr_pld.attr, - NULL, -}; - -static struct attribute_group nhmex_uncore_mbox_format_group = { - .name = "format", - .attrs = nhmex_uncore_mbox_formats_attr, -}; - -static struct uncore_event_desc nhmex_uncore_mbox_events[] = { - INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x2800"), - INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x2820"), - { /* end: all zeroes */ }, -}; - -static struct uncore_event_desc wsmex_uncore_mbox_events[] = { - INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x5000"), - INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x5040"), - { /* end: all zeroes */ }, -}; - -static struct intel_uncore_ops nhmex_uncore_mbox_ops = { - NHMEX_UNCORE_OPS_COMMON_INIT(), - .enable_event = nhmex_mbox_msr_enable_event, - .hw_config = nhmex_mbox_hw_config, - .get_constraint = nhmex_mbox_get_constraint, - .put_constraint = nhmex_mbox_put_constraint, -}; - -static struct intel_uncore_type nhmex_uncore_mbox = { - .name = "mbox", - .num_counters = 6, - .num_boxes = 2, - .perf_ctr_bits = 48, - .event_ctl = NHMEX_M0_MSR_PMU_CTL0, - .perf_ctr = NHMEX_M0_MSR_PMU_CNT0, - .event_mask = NHMEX_M_PMON_RAW_EVENT_MASK, - .box_ctl = NHMEX_M0_MSR_GLOBAL_CTL, - .msr_offset = NHMEX_M_MSR_OFFSET, - .pair_ctr_ctl = 1, - .num_shared_regs = 8, - .event_descs = nhmex_uncore_mbox_events, - .ops = &nhmex_uncore_mbox_ops, - .format_group = &nhmex_uncore_mbox_format_group, -}; - -static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - - /* adjust the main event selector and extra register index */ - if (reg1->idx % 2) { - reg1->idx--; - hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT; - } else { - reg1->idx++; - hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT; - } - - /* adjust extra register config */ - switch (reg1->idx % 6) { - case 2: - /* shift the 8~15 bits to the 0~7 bits */ - reg1->config >>= 8; - break; - case 3: - /* shift the 0~7 bits to the 8~15 bits */ - reg1->config <<= 8; - break; - }; -} - -/* - * Each rbox has 4 event set which monitor PQI port 0~3 or 4~7. - * An event set consists of 6 events, the 3rd and 4th events in - * an event set use the same extra register. So an event set uses - * 5 extra registers. - */ -static struct event_constraint * -nhmex_rbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - struct hw_perf_event_extra *reg2 = &hwc->branch_reg; - struct intel_uncore_extra_reg *er; - unsigned long flags; - int idx, er_idx; - u64 config1; - bool ok = false; - - if (!uncore_box_is_fake(box) && reg1->alloc) - return NULL; - - idx = reg1->idx % 6; - config1 = reg1->config; -again: - er_idx = idx; - /* the 3rd and 4th events use the same extra register */ - if (er_idx > 2) - er_idx--; - er_idx += (reg1->idx / 6) * 5; - - er = &box->shared_regs[er_idx]; - raw_spin_lock_irqsave(&er->lock, flags); - if (idx < 2) { - if (!atomic_read(&er->ref) || er->config == reg1->config) { - atomic_inc(&er->ref); - er->config = reg1->config; - ok = true; - } - } else if (idx == 2 || idx == 3) { - /* - * these two events use different fields in a extra register, - * the 0~7 bits and the 8~15 bits respectively. - */ - u64 mask = 0xff << ((idx - 2) * 8); - if (!__BITS_VALUE(atomic_read(&er->ref), idx - 2, 8) || - !((er->config ^ config1) & mask)) { - atomic_add(1 << ((idx - 2) * 8), &er->ref); - er->config &= ~mask; - er->config |= config1 & mask; - ok = true; - } - } else { - if (!atomic_read(&er->ref) || - (er->config == (hwc->config >> 32) && - er->config1 == reg1->config && - er->config2 == reg2->config)) { - atomic_inc(&er->ref); - er->config = (hwc->config >> 32); - er->config1 = reg1->config; - er->config2 = reg2->config; - ok = true; - } - } - raw_spin_unlock_irqrestore(&er->lock, flags); - - if (!ok) { - /* - * The Rbox events are always in pairs. The paired - * events are functional identical, but use different - * extra registers. If we failed to take an extra - * register, try the alternative. - */ - idx ^= 1; - if (idx != reg1->idx % 6) { - if (idx == 2) - config1 >>= 8; - else if (idx == 3) - config1 <<= 8; - goto again; - } - } else { - if (!uncore_box_is_fake(box)) { - if (idx != reg1->idx % 6) - nhmex_rbox_alter_er(box, event); - reg1->alloc = 1; - } - return NULL; - } - return &uncore_constraint_empty; -} - -static void nhmex_rbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event) -{ - struct intel_uncore_extra_reg *er; - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - int idx, er_idx; - - if (uncore_box_is_fake(box) || !reg1->alloc) - return; - - idx = reg1->idx % 6; - er_idx = idx; - if (er_idx > 2) - er_idx--; - er_idx += (reg1->idx / 6) * 5; - - er = &box->shared_regs[er_idx]; - if (idx == 2 || idx == 3) - atomic_sub(1 << ((idx - 2) * 8), &er->ref); - else - atomic_dec(&er->ref); - - reg1->alloc = 0; -} - -static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; - struct hw_perf_event_extra *reg2 = &event->hw.branch_reg; - int idx; - - idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >> - NHMEX_R_PMON_CTL_EV_SEL_SHIFT; - if (idx >= 0x18) - return -EINVAL; - - reg1->idx = idx; - reg1->config = event->attr.config1; - - switch (idx % 6) { - case 4: - case 5: - hwc->config |= event->attr.config & (~0ULL << 32); - reg2->config = event->attr.config2; - break; - }; - return 0; -} - -static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - struct hw_perf_event_extra *reg1 = &hwc->extra_reg; - struct hw_perf_event_extra *reg2 = &hwc->branch_reg; - int idx, port; - - idx = reg1->idx; - port = idx / 6 + box->pmu->pmu_idx * 4; - - switch (idx % 6) { - case 0: - wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG0(port), reg1->config); - break; - case 1: - wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG1(port), reg1->config); - break; - case 2: - case 3: - wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port), - uncore_shared_reg_config(box, 2 + (idx / 6) * 5)); - break; - case 4: - wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port), - hwc->config >> 32); - wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(port), reg1->config); - wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MASK(port), reg2->config); - break; - case 5: - wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port), - hwc->config >> 32); - wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config); - wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config); - break; - }; - - wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 | - (hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK)); -} - -DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config:32-63"); -DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config1:0-63"); -DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63"); -DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15"); -DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31"); - -static struct attribute *nhmex_uncore_rbox_formats_attr[] = { - &format_attr_event5.attr, - &format_attr_xbr_mm_cfg.attr, - &format_attr_xbr_match.attr, - &format_attr_xbr_mask.attr, - &format_attr_qlx_cfg.attr, - &format_attr_iperf_cfg.attr, - NULL, -}; - -static struct attribute_group nhmex_uncore_rbox_format_group = { - .name = "format", - .attrs = nhmex_uncore_rbox_formats_attr, -}; - -static struct uncore_event_desc nhmex_uncore_rbox_events[] = { - INTEL_UNCORE_EVENT_DESC(qpi0_flit_send, "event=0x0,iperf_cfg=0x80000000"), - INTEL_UNCORE_EVENT_DESC(qpi1_filt_send, "event=0x6,iperf_cfg=0x80000000"), - INTEL_UNCORE_EVENT_DESC(qpi0_idle_filt, "event=0x0,iperf_cfg=0x40000000"), - INTEL_UNCORE_EVENT_DESC(qpi1_idle_filt, "event=0x6,iperf_cfg=0x40000000"), - INTEL_UNCORE_EVENT_DESC(qpi0_date_response, "event=0x0,iperf_cfg=0xc4"), - INTEL_UNCORE_EVENT_DESC(qpi1_date_response, "event=0x6,iperf_cfg=0xc4"), - { /* end: all zeroes */ }, -}; - -static struct intel_uncore_ops nhmex_uncore_rbox_ops = { - NHMEX_UNCORE_OPS_COMMON_INIT(), - .enable_event = nhmex_rbox_msr_enable_event, - .hw_config = nhmex_rbox_hw_config, - .get_constraint = nhmex_rbox_get_constraint, - .put_constraint = nhmex_rbox_put_constraint, -}; - -static struct intel_uncore_type nhmex_uncore_rbox = { - .name = "rbox", - .num_counters = 8, - .num_boxes = 2, - .perf_ctr_bits = 48, - .event_ctl = NHMEX_R_MSR_PMON_CTL0, - .perf_ctr = NHMEX_R_MSR_PMON_CNT0, - .event_mask = NHMEX_R_PMON_RAW_EVENT_MASK, - .box_ctl = NHMEX_R_MSR_GLOBAL_CTL, - .msr_offset = NHMEX_R_MSR_OFFSET, - .pair_ctr_ctl = 1, - .num_shared_regs = 20, - .event_descs = nhmex_uncore_rbox_events, - .ops = &nhmex_uncore_rbox_ops, - .format_group = &nhmex_uncore_rbox_format_group -}; - -static struct intel_uncore_type *nhmex_msr_uncores[] = { - &nhmex_uncore_ubox, - &nhmex_uncore_cbox, - &nhmex_uncore_bbox, - &nhmex_uncore_sbox, - &nhmex_uncore_mbox, - &nhmex_uncore_rbox, - &nhmex_uncore_wbox, - NULL, -}; -/* end of Nehalem-EX uncore support */ - static void uncore_assign_hw_event(struct intel_uncore_box *box, struct perf_event *event, int idx) { struct hw_perf_event *hwc = &event->hw; @@ -2195,9 +1167,8 @@ static void __init uncore_cpu_setup(void *dummy) static int __init uncore_cpu_init(void) { - int ret, max_cores; + int ret; - max_cores = boot_cpu_data.x86_max_cores; switch (boot_cpu_data.x86_model) { case 26: /* Nehalem */ case 30: @@ -2213,13 +1184,8 @@ static int __init uncore_cpu_init(void) snbep_uncore_cpu_init(); break; case 46: /* Nehalem-EX */ - uncore_nhmex = true; case 47: /* Westmere-EX aka. Xeon E7 */ - if (!uncore_nhmex) - nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events; - if (nhmex_uncore_cbox.num_boxes > max_cores) - nhmex_uncore_cbox.num_boxes = max_cores; - uncore_msr_uncores = nhmex_msr_uncores; + nhmex_uncore_cpu_init(); break; case 62: /* IvyTown */ ivt_uncore_cpu_init(); diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index 538be93b5f19..b91559936d49 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -24,188 +24,6 @@ #define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff) -/* NHM-EX event control */ -#define NHMEX_PMON_CTL_EV_SEL_MASK 0x000000ff -#define NHMEX_PMON_CTL_UMASK_MASK 0x0000ff00 -#define NHMEX_PMON_CTL_EN_BIT0 (1 << 0) -#define NHMEX_PMON_CTL_EDGE_DET (1 << 18) -#define NHMEX_PMON_CTL_PMI_EN (1 << 20) -#define NHMEX_PMON_CTL_EN_BIT22 (1 << 22) -#define NHMEX_PMON_CTL_INVERT (1 << 23) -#define NHMEX_PMON_CTL_TRESH_MASK 0xff000000 -#define NHMEX_PMON_RAW_EVENT_MASK (NHMEX_PMON_CTL_EV_SEL_MASK | \ - NHMEX_PMON_CTL_UMASK_MASK | \ - NHMEX_PMON_CTL_EDGE_DET | \ - NHMEX_PMON_CTL_INVERT | \ - NHMEX_PMON_CTL_TRESH_MASK) - -/* NHM-EX Ubox */ -#define NHMEX_U_MSR_PMON_GLOBAL_CTL 0xc00 -#define NHMEX_U_MSR_PMON_CTR 0xc11 -#define NHMEX_U_MSR_PMON_EV_SEL 0xc10 - -#define NHMEX_U_PMON_GLOBAL_EN (1 << 0) -#define NHMEX_U_PMON_GLOBAL_PMI_CORE_SEL 0x0000001e -#define NHMEX_U_PMON_GLOBAL_EN_ALL (1 << 28) -#define NHMEX_U_PMON_GLOBAL_RST_ALL (1 << 29) -#define NHMEX_U_PMON_GLOBAL_FRZ_ALL (1 << 31) - -#define NHMEX_U_PMON_RAW_EVENT_MASK \ - (NHMEX_PMON_CTL_EV_SEL_MASK | \ - NHMEX_PMON_CTL_EDGE_DET) - -/* NHM-EX Cbox */ -#define NHMEX_C0_MSR_PMON_GLOBAL_CTL 0xd00 -#define NHMEX_C0_MSR_PMON_CTR0 0xd11 -#define NHMEX_C0_MSR_PMON_EV_SEL0 0xd10 -#define NHMEX_C_MSR_OFFSET 0x20 - -/* NHM-EX Bbox */ -#define NHMEX_B0_MSR_PMON_GLOBAL_CTL 0xc20 -#define NHMEX_B0_MSR_PMON_CTR0 0xc31 -#define NHMEX_B0_MSR_PMON_CTL0 0xc30 -#define NHMEX_B_MSR_OFFSET 0x40 -#define NHMEX_B0_MSR_MATCH 0xe45 -#define NHMEX_B0_MSR_MASK 0xe46 -#define NHMEX_B1_MSR_MATCH 0xe4d -#define NHMEX_B1_MSR_MASK 0xe4e - -#define NHMEX_B_PMON_CTL_EN (1 << 0) -#define NHMEX_B_PMON_CTL_EV_SEL_SHIFT 1 -#define NHMEX_B_PMON_CTL_EV_SEL_MASK \ - (0x1f << NHMEX_B_PMON_CTL_EV_SEL_SHIFT) -#define NHMEX_B_PMON_CTR_SHIFT 6 -#define NHMEX_B_PMON_CTR_MASK \ - (0x3 << NHMEX_B_PMON_CTR_SHIFT) -#define NHMEX_B_PMON_RAW_EVENT_MASK \ - (NHMEX_B_PMON_CTL_EV_SEL_MASK | \ - NHMEX_B_PMON_CTR_MASK) - -/* NHM-EX Sbox */ -#define NHMEX_S0_MSR_PMON_GLOBAL_CTL 0xc40 -#define NHMEX_S0_MSR_PMON_CTR0 0xc51 -#define NHMEX_S0_MSR_PMON_CTL0 0xc50 -#define NHMEX_S_MSR_OFFSET 0x80 -#define NHMEX_S0_MSR_MM_CFG 0xe48 -#define NHMEX_S0_MSR_MATCH 0xe49 -#define NHMEX_S0_MSR_MASK 0xe4a -#define NHMEX_S1_MSR_MM_CFG 0xe58 -#define NHMEX_S1_MSR_MATCH 0xe59 -#define NHMEX_S1_MSR_MASK 0xe5a - -#define NHMEX_S_PMON_MM_CFG_EN (0x1ULL << 63) -#define NHMEX_S_EVENT_TO_R_PROG_EV 0 - -/* NHM-EX Mbox */ -#define NHMEX_M0_MSR_GLOBAL_CTL 0xca0 -#define NHMEX_M0_MSR_PMU_DSP 0xca5 -#define NHMEX_M0_MSR_PMU_ISS 0xca6 -#define NHMEX_M0_MSR_PMU_MAP 0xca7 -#define NHMEX_M0_MSR_PMU_MSC_THR 0xca8 -#define NHMEX_M0_MSR_PMU_PGT 0xca9 -#define NHMEX_M0_MSR_PMU_PLD 0xcaa -#define NHMEX_M0_MSR_PMU_ZDP_CTL_FVC 0xcab -#define NHMEX_M0_MSR_PMU_CTL0 0xcb0 -#define NHMEX_M0_MSR_PMU_CNT0 0xcb1 -#define NHMEX_M_MSR_OFFSET 0x40 -#define NHMEX_M0_MSR_PMU_MM_CFG 0xe54 -#define NHMEX_M1_MSR_PMU_MM_CFG 0xe5c - -#define NHMEX_M_PMON_MM_CFG_EN (1ULL << 63) -#define NHMEX_M_PMON_ADDR_MATCH_MASK 0x3ffffffffULL -#define NHMEX_M_PMON_ADDR_MASK_MASK 0x7ffffffULL -#define NHMEX_M_PMON_ADDR_MASK_SHIFT 34 - -#define NHMEX_M_PMON_CTL_EN (1 << 0) -#define NHMEX_M_PMON_CTL_PMI_EN (1 << 1) -#define NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT 2 -#define NHMEX_M_PMON_CTL_COUNT_MODE_MASK \ - (0x3 << NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT) -#define NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT 4 -#define NHMEX_M_PMON_CTL_STORAGE_MODE_MASK \ - (0x3 << NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT) -#define NHMEX_M_PMON_CTL_WRAP_MODE (1 << 6) -#define NHMEX_M_PMON_CTL_FLAG_MODE (1 << 7) -#define NHMEX_M_PMON_CTL_INC_SEL_SHIFT 9 -#define NHMEX_M_PMON_CTL_INC_SEL_MASK \ - (0x1f << NHMEX_M_PMON_CTL_INC_SEL_SHIFT) -#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT 19 -#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK \ - (0x7 << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) -#define NHMEX_M_PMON_RAW_EVENT_MASK \ - (NHMEX_M_PMON_CTL_COUNT_MODE_MASK | \ - NHMEX_M_PMON_CTL_STORAGE_MODE_MASK | \ - NHMEX_M_PMON_CTL_WRAP_MODE | \ - NHMEX_M_PMON_CTL_FLAG_MODE | \ - NHMEX_M_PMON_CTL_INC_SEL_MASK | \ - NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK) - -#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK (((1 << 11) - 1) | (1 << 23)) -#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (11 + 3 * (n))) - -#define WSMEX_M_PMON_ZDP_CTL_FVC_MASK (((1 << 12) - 1) | (1 << 24)) -#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (12 + 3 * (n))) - -/* - * use the 9~13 bits to select event If the 7th bit is not set, - * otherwise use the 19~21 bits to select event. - */ -#define MBOX_INC_SEL(x) ((x) << NHMEX_M_PMON_CTL_INC_SEL_SHIFT) -#define MBOX_SET_FLAG_SEL(x) (((x) << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) | \ - NHMEX_M_PMON_CTL_FLAG_MODE) -#define MBOX_INC_SEL_MASK (NHMEX_M_PMON_CTL_INC_SEL_MASK | \ - NHMEX_M_PMON_CTL_FLAG_MODE) -#define MBOX_SET_FLAG_SEL_MASK (NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK | \ - NHMEX_M_PMON_CTL_FLAG_MODE) -#define MBOX_INC_SEL_EXTAR_REG(c, r) \ - EVENT_EXTRA_REG(MBOX_INC_SEL(c), NHMEX_M0_MSR_PMU_##r, \ - MBOX_INC_SEL_MASK, (u64)-1, NHMEX_M_##r) -#define MBOX_SET_FLAG_SEL_EXTRA_REG(c, r) \ - EVENT_EXTRA_REG(MBOX_SET_FLAG_SEL(c), NHMEX_M0_MSR_PMU_##r, \ - MBOX_SET_FLAG_SEL_MASK, \ - (u64)-1, NHMEX_M_##r) - -/* NHM-EX Rbox */ -#define NHMEX_R_MSR_GLOBAL_CTL 0xe00 -#define NHMEX_R_MSR_PMON_CTL0 0xe10 -#define NHMEX_R_MSR_PMON_CNT0 0xe11 -#define NHMEX_R_MSR_OFFSET 0x20 - -#define NHMEX_R_MSR_PORTN_QLX_CFG(n) \ - ((n) < 4 ? (0xe0c + (n)) : (0xe2c + (n) - 4)) -#define NHMEX_R_MSR_PORTN_IPERF_CFG0(n) (0xe04 + (n)) -#define NHMEX_R_MSR_PORTN_IPERF_CFG1(n) (0xe24 + (n)) -#define NHMEX_R_MSR_PORTN_XBR_OFFSET(n) \ - (((n) < 4 ? 0 : 0x10) + (n) * 4) -#define NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) \ - (0xe60 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n)) -#define NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(n) \ - (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 1) -#define NHMEX_R_MSR_PORTN_XBR_SET1_MASK(n) \ - (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 2) -#define NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) \ - (0xe70 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n)) -#define NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(n) \ - (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 1) -#define NHMEX_R_MSR_PORTN_XBR_SET2_MASK(n) \ - (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 2) - -#define NHMEX_R_PMON_CTL_EN (1 << 0) -#define NHMEX_R_PMON_CTL_EV_SEL_SHIFT 1 -#define NHMEX_R_PMON_CTL_EV_SEL_MASK \ - (0x1f << NHMEX_R_PMON_CTL_EV_SEL_SHIFT) -#define NHMEX_R_PMON_CTL_PMI_EN (1 << 6) -#define NHMEX_R_PMON_RAW_EVENT_MASK NHMEX_R_PMON_CTL_EV_SEL_MASK - -/* NHM-EX Wbox */ -#define NHMEX_W_MSR_GLOBAL_CTL 0xc80 -#define NHMEX_W_MSR_PMON_CNT0 0xc90 -#define NHMEX_W_MSR_PMON_EVT_SEL0 0xc91 -#define NHMEX_W_MSR_PMON_FIXED_CTR 0x394 -#define NHMEX_W_MSR_PMON_FIXED_CTL 0x395 - -#define NHMEX_W_PMON_GLOBAL_FIXED_EN (1ULL << 31) - struct intel_uncore_ops; struct intel_uncore_pmu; struct intel_uncore_box; @@ -514,3 +332,6 @@ int snbep_uncore_pci_init(void); void snbep_uncore_cpu_init(void); int ivt_uncore_pci_init(void); void ivt_uncore_cpu_init(void); + +/* perf_event_intel_uncore_nhmex.c */ +void nhmex_uncore_cpu_init(void); diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c new file mode 100644 index 000000000000..93b11a8f110d --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c @@ -0,0 +1,1221 @@ +/* Nehalem-EX/Westmere-EX uncore support */ +#include "perf_event_intel_uncore.h" + +/* NHM-EX event control */ +#define NHMEX_PMON_CTL_EV_SEL_MASK 0x000000ff +#define NHMEX_PMON_CTL_UMASK_MASK 0x0000ff00 +#define NHMEX_PMON_CTL_EN_BIT0 (1 << 0) +#define NHMEX_PMON_CTL_EDGE_DET (1 << 18) +#define NHMEX_PMON_CTL_PMI_EN (1 << 20) +#define NHMEX_PMON_CTL_EN_BIT22 (1 << 22) +#define NHMEX_PMON_CTL_INVERT (1 << 23) +#define NHMEX_PMON_CTL_TRESH_MASK 0xff000000 +#define NHMEX_PMON_RAW_EVENT_MASK (NHMEX_PMON_CTL_EV_SEL_MASK | \ + NHMEX_PMON_CTL_UMASK_MASK | \ + NHMEX_PMON_CTL_EDGE_DET | \ + NHMEX_PMON_CTL_INVERT | \ + NHMEX_PMON_CTL_TRESH_MASK) + +/* NHM-EX Ubox */ +#define NHMEX_U_MSR_PMON_GLOBAL_CTL 0xc00 +#define NHMEX_U_MSR_PMON_CTR 0xc11 +#define NHMEX_U_MSR_PMON_EV_SEL 0xc10 + +#define NHMEX_U_PMON_GLOBAL_EN (1 << 0) +#define NHMEX_U_PMON_GLOBAL_PMI_CORE_SEL 0x0000001e +#define NHMEX_U_PMON_GLOBAL_EN_ALL (1 << 28) +#define NHMEX_U_PMON_GLOBAL_RST_ALL (1 << 29) +#define NHMEX_U_PMON_GLOBAL_FRZ_ALL (1 << 31) + +#define NHMEX_U_PMON_RAW_EVENT_MASK \ + (NHMEX_PMON_CTL_EV_SEL_MASK | \ + NHMEX_PMON_CTL_EDGE_DET) + +/* NHM-EX Cbox */ +#define NHMEX_C0_MSR_PMON_GLOBAL_CTL 0xd00 +#define NHMEX_C0_MSR_PMON_CTR0 0xd11 +#define NHMEX_C0_MSR_PMON_EV_SEL0 0xd10 +#define NHMEX_C_MSR_OFFSET 0x20 + +/* NHM-EX Bbox */ +#define NHMEX_B0_MSR_PMON_GLOBAL_CTL 0xc20 +#define NHMEX_B0_MSR_PMON_CTR0 0xc31 +#define NHMEX_B0_MSR_PMON_CTL0 0xc30 +#define NHMEX_B_MSR_OFFSET 0x40 +#define NHMEX_B0_MSR_MATCH 0xe45 +#define NHMEX_B0_MSR_MASK 0xe46 +#define NHMEX_B1_MSR_MATCH 0xe4d +#define NHMEX_B1_MSR_MASK 0xe4e + +#define NHMEX_B_PMON_CTL_EN (1 << 0) +#define NHMEX_B_PMON_CTL_EV_SEL_SHIFT 1 +#define NHMEX_B_PMON_CTL_EV_SEL_MASK \ + (0x1f << NHMEX_B_PMON_CTL_EV_SEL_SHIFT) +#define NHMEX_B_PMON_CTR_SHIFT 6 +#define NHMEX_B_PMON_CTR_MASK \ + (0x3 << NHMEX_B_PMON_CTR_SHIFT) +#define NHMEX_B_PMON_RAW_EVENT_MASK \ + (NHMEX_B_PMON_CTL_EV_SEL_MASK | \ + NHMEX_B_PMON_CTR_MASK) + +/* NHM-EX Sbox */ +#define NHMEX_S0_MSR_PMON_GLOBAL_CTL 0xc40 +#define NHMEX_S0_MSR_PMON_CTR0 0xc51 +#define NHMEX_S0_MSR_PMON_CTL0 0xc50 +#define NHMEX_S_MSR_OFFSET 0x80 +#define NHMEX_S0_MSR_MM_CFG 0xe48 +#define NHMEX_S0_MSR_MATCH 0xe49 +#define NHMEX_S0_MSR_MASK 0xe4a +#define NHMEX_S1_MSR_MM_CFG 0xe58 +#define NHMEX_S1_MSR_MATCH 0xe59 +#define NHMEX_S1_MSR_MASK 0xe5a + +#define NHMEX_S_PMON_MM_CFG_EN (0x1ULL << 63) +#define NHMEX_S_EVENT_TO_R_PROG_EV 0 + +/* NHM-EX Mbox */ +#define NHMEX_M0_MSR_GLOBAL_CTL 0xca0 +#define NHMEX_M0_MSR_PMU_DSP 0xca5 +#define NHMEX_M0_MSR_PMU_ISS 0xca6 +#define NHMEX_M0_MSR_PMU_MAP 0xca7 +#define NHMEX_M0_MSR_PMU_MSC_THR 0xca8 +#define NHMEX_M0_MSR_PMU_PGT 0xca9 +#define NHMEX_M0_MSR_PMU_PLD 0xcaa +#define NHMEX_M0_MSR_PMU_ZDP_CTL_FVC 0xcab +#define NHMEX_M0_MSR_PMU_CTL0 0xcb0 +#define NHMEX_M0_MSR_PMU_CNT0 0xcb1 +#define NHMEX_M_MSR_OFFSET 0x40 +#define NHMEX_M0_MSR_PMU_MM_CFG 0xe54 +#define NHMEX_M1_MSR_PMU_MM_CFG 0xe5c + +#define NHMEX_M_PMON_MM_CFG_EN (1ULL << 63) +#define NHMEX_M_PMON_ADDR_MATCH_MASK 0x3ffffffffULL +#define NHMEX_M_PMON_ADDR_MASK_MASK 0x7ffffffULL +#define NHMEX_M_PMON_ADDR_MASK_SHIFT 34 + +#define NHMEX_M_PMON_CTL_EN (1 << 0) +#define NHMEX_M_PMON_CTL_PMI_EN (1 << 1) +#define NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT 2 +#define NHMEX_M_PMON_CTL_COUNT_MODE_MASK \ + (0x3 << NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT) +#define NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT 4 +#define NHMEX_M_PMON_CTL_STORAGE_MODE_MASK \ + (0x3 << NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT) +#define NHMEX_M_PMON_CTL_WRAP_MODE (1 << 6) +#define NHMEX_M_PMON_CTL_FLAG_MODE (1 << 7) +#define NHMEX_M_PMON_CTL_INC_SEL_SHIFT 9 +#define NHMEX_M_PMON_CTL_INC_SEL_MASK \ + (0x1f << NHMEX_M_PMON_CTL_INC_SEL_SHIFT) +#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT 19 +#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK \ + (0x7 << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) +#define NHMEX_M_PMON_RAW_EVENT_MASK \ + (NHMEX_M_PMON_CTL_COUNT_MODE_MASK | \ + NHMEX_M_PMON_CTL_STORAGE_MODE_MASK | \ + NHMEX_M_PMON_CTL_WRAP_MODE | \ + NHMEX_M_PMON_CTL_FLAG_MODE | \ + NHMEX_M_PMON_CTL_INC_SEL_MASK | \ + NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK) + +#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK (((1 << 11) - 1) | (1 << 23)) +#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (11 + 3 * (n))) + +#define WSMEX_M_PMON_ZDP_CTL_FVC_MASK (((1 << 12) - 1) | (1 << 24)) +#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (12 + 3 * (n))) + +/* + * use the 9~13 bits to select event If the 7th bit is not set, + * otherwise use the 19~21 bits to select event. + */ +#define MBOX_INC_SEL(x) ((x) << NHMEX_M_PMON_CTL_INC_SEL_SHIFT) +#define MBOX_SET_FLAG_SEL(x) (((x) << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) | \ + NHMEX_M_PMON_CTL_FLAG_MODE) +#define MBOX_INC_SEL_MASK (NHMEX_M_PMON_CTL_INC_SEL_MASK | \ + NHMEX_M_PMON_CTL_FLAG_MODE) +#define MBOX_SET_FLAG_SEL_MASK (NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK | \ + NHMEX_M_PMON_CTL_FLAG_MODE) +#define MBOX_INC_SEL_EXTAR_REG(c, r) \ + EVENT_EXTRA_REG(MBOX_INC_SEL(c), NHMEX_M0_MSR_PMU_##r, \ + MBOX_INC_SEL_MASK, (u64)-1, NHMEX_M_##r) +#define MBOX_SET_FLAG_SEL_EXTRA_REG(c, r) \ + EVENT_EXTRA_REG(MBOX_SET_FLAG_SEL(c), NHMEX_M0_MSR_PMU_##r, \ + MBOX_SET_FLAG_SEL_MASK, \ + (u64)-1, NHMEX_M_##r) + +/* NHM-EX Rbox */ +#define NHMEX_R_MSR_GLOBAL_CTL 0xe00 +#define NHMEX_R_MSR_PMON_CTL0 0xe10 +#define NHMEX_R_MSR_PMON_CNT0 0xe11 +#define NHMEX_R_MSR_OFFSET 0x20 + +#define NHMEX_R_MSR_PORTN_QLX_CFG(n) \ + ((n) < 4 ? (0xe0c + (n)) : (0xe2c + (n) - 4)) +#define NHMEX_R_MSR_PORTN_IPERF_CFG0(n) (0xe04 + (n)) +#define NHMEX_R_MSR_PORTN_IPERF_CFG1(n) (0xe24 + (n)) +#define NHMEX_R_MSR_PORTN_XBR_OFFSET(n) \ + (((n) < 4 ? 0 : 0x10) + (n) * 4) +#define NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) \ + (0xe60 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n)) +#define NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(n) \ + (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 1) +#define NHMEX_R_MSR_PORTN_XBR_SET1_MASK(n) \ + (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 2) +#define NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) \ + (0xe70 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n)) +#define NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(n) \ + (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 1) +#define NHMEX_R_MSR_PORTN_XBR_SET2_MASK(n) \ + (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 2) + +#define NHMEX_R_PMON_CTL_EN (1 << 0) +#define NHMEX_R_PMON_CTL_EV_SEL_SHIFT 1 +#define NHMEX_R_PMON_CTL_EV_SEL_MASK \ + (0x1f << NHMEX_R_PMON_CTL_EV_SEL_SHIFT) +#define NHMEX_R_PMON_CTL_PMI_EN (1 << 6) +#define NHMEX_R_PMON_RAW_EVENT_MASK NHMEX_R_PMON_CTL_EV_SEL_MASK + +/* NHM-EX Wbox */ +#define NHMEX_W_MSR_GLOBAL_CTL 0xc80 +#define NHMEX_W_MSR_PMON_CNT0 0xc90 +#define NHMEX_W_MSR_PMON_EVT_SEL0 0xc91 +#define NHMEX_W_MSR_PMON_FIXED_CTR 0x394 +#define NHMEX_W_MSR_PMON_FIXED_CTL 0x395 + +#define NHMEX_W_PMON_GLOBAL_FIXED_EN (1ULL << 31) + +#define __BITS_VALUE(x, i, n) ((typeof(x))(((x) >> ((i) * (n))) & \ + ((1ULL << (n)) - 1))) + +DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); +DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5"); +DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); +DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); +DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); +DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31"); +DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7"); +DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63"); +DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63"); + +static void nhmex_uncore_msr_init_box(struct intel_uncore_box *box) +{ + wrmsrl(NHMEX_U_MSR_PMON_GLOBAL_CTL, NHMEX_U_PMON_GLOBAL_EN_ALL); +} + +static void nhmex_uncore_msr_disable_box(struct intel_uncore_box *box) +{ + unsigned msr = uncore_msr_box_ctl(box); + u64 config; + + if (msr) { + rdmsrl(msr, config); + config &= ~((1ULL << uncore_num_counters(box)) - 1); + /* WBox has a fixed counter */ + if (uncore_msr_fixed_ctl(box)) + config &= ~NHMEX_W_PMON_GLOBAL_FIXED_EN; + wrmsrl(msr, config); + } +} + +static void nhmex_uncore_msr_enable_box(struct intel_uncore_box *box) +{ + unsigned msr = uncore_msr_box_ctl(box); + u64 config; + + if (msr) { + rdmsrl(msr, config); + config |= (1ULL << uncore_num_counters(box)) - 1; + /* WBox has a fixed counter */ + if (uncore_msr_fixed_ctl(box)) + config |= NHMEX_W_PMON_GLOBAL_FIXED_EN; + wrmsrl(msr, config); + } +} + +static void nhmex_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + wrmsrl(event->hw.config_base, 0); +} + +static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + if (hwc->idx >= UNCORE_PMC_IDX_FIXED) + wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0); + else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0) + wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22); + else + wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0); +} + +#define NHMEX_UNCORE_OPS_COMMON_INIT() \ + .init_box = nhmex_uncore_msr_init_box, \ + .disable_box = nhmex_uncore_msr_disable_box, \ + .enable_box = nhmex_uncore_msr_enable_box, \ + .disable_event = nhmex_uncore_msr_disable_event, \ + .read_counter = uncore_msr_read_counter + +static struct intel_uncore_ops nhmex_uncore_ops = { + NHMEX_UNCORE_OPS_COMMON_INIT(), + .enable_event = nhmex_uncore_msr_enable_event, +}; + +static struct attribute *nhmex_uncore_ubox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_edge.attr, + NULL, +}; + +static struct attribute_group nhmex_uncore_ubox_format_group = { + .name = "format", + .attrs = nhmex_uncore_ubox_formats_attr, +}; + +static struct intel_uncore_type nhmex_uncore_ubox = { + .name = "ubox", + .num_counters = 1, + .num_boxes = 1, + .perf_ctr_bits = 48, + .event_ctl = NHMEX_U_MSR_PMON_EV_SEL, + .perf_ctr = NHMEX_U_MSR_PMON_CTR, + .event_mask = NHMEX_U_PMON_RAW_EVENT_MASK, + .box_ctl = NHMEX_U_MSR_PMON_GLOBAL_CTL, + .ops = &nhmex_uncore_ops, + .format_group = &nhmex_uncore_ubox_format_group +}; + +static struct attribute *nhmex_uncore_cbox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh8.attr, + NULL, +}; + +static struct attribute_group nhmex_uncore_cbox_format_group = { + .name = "format", + .attrs = nhmex_uncore_cbox_formats_attr, +}; + +/* msr offset for each instance of cbox */ +static unsigned nhmex_cbox_msr_offsets[] = { + 0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0, +}; + +static struct intel_uncore_type nhmex_uncore_cbox = { + .name = "cbox", + .num_counters = 6, + .num_boxes = 10, + .perf_ctr_bits = 48, + .event_ctl = NHMEX_C0_MSR_PMON_EV_SEL0, + .perf_ctr = NHMEX_C0_MSR_PMON_CTR0, + .event_mask = NHMEX_PMON_RAW_EVENT_MASK, + .box_ctl = NHMEX_C0_MSR_PMON_GLOBAL_CTL, + .msr_offsets = nhmex_cbox_msr_offsets, + .pair_ctr_ctl = 1, + .ops = &nhmex_uncore_ops, + .format_group = &nhmex_uncore_cbox_format_group +}; + +static struct uncore_event_desc nhmex_uncore_wbox_events[] = { + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0"), + { /* end: all zeroes */ }, +}; + +static struct intel_uncore_type nhmex_uncore_wbox = { + .name = "wbox", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .event_ctl = NHMEX_W_MSR_PMON_CNT0, + .perf_ctr = NHMEX_W_MSR_PMON_EVT_SEL0, + .fixed_ctr = NHMEX_W_MSR_PMON_FIXED_CTR, + .fixed_ctl = NHMEX_W_MSR_PMON_FIXED_CTL, + .event_mask = NHMEX_PMON_RAW_EVENT_MASK, + .box_ctl = NHMEX_W_MSR_GLOBAL_CTL, + .pair_ctr_ctl = 1, + .event_descs = nhmex_uncore_wbox_events, + .ops = &nhmex_uncore_ops, + .format_group = &nhmex_uncore_cbox_format_group +}; + +static int nhmex_bbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + struct hw_perf_event_extra *reg2 = &hwc->branch_reg; + int ctr, ev_sel; + + ctr = (hwc->config & NHMEX_B_PMON_CTR_MASK) >> + NHMEX_B_PMON_CTR_SHIFT; + ev_sel = (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK) >> + NHMEX_B_PMON_CTL_EV_SEL_SHIFT; + + /* events that do not use the match/mask registers */ + if ((ctr == 0 && ev_sel > 0x3) || (ctr == 1 && ev_sel > 0x6) || + (ctr == 2 && ev_sel != 0x4) || ctr == 3) + return 0; + + if (box->pmu->pmu_idx == 0) + reg1->reg = NHMEX_B0_MSR_MATCH; + else + reg1->reg = NHMEX_B1_MSR_MATCH; + reg1->idx = 0; + reg1->config = event->attr.config1; + reg2->config = event->attr.config2; + return 0; +} + +static void nhmex_bbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + struct hw_perf_event_extra *reg2 = &hwc->branch_reg; + + if (reg1->idx != EXTRA_REG_NONE) { + wrmsrl(reg1->reg, reg1->config); + wrmsrl(reg1->reg + 1, reg2->config); + } + wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 | + (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK)); +} + +/* + * The Bbox has 4 counters, but each counter monitors different events. + * Use bits 6-7 in the event config to select counter. + */ +static struct event_constraint nhmex_uncore_bbox_constraints[] = { + EVENT_CONSTRAINT(0 , 1, 0xc0), + EVENT_CONSTRAINT(0x40, 2, 0xc0), + EVENT_CONSTRAINT(0x80, 4, 0xc0), + EVENT_CONSTRAINT(0xc0, 8, 0xc0), + EVENT_CONSTRAINT_END, +}; + +static struct attribute *nhmex_uncore_bbox_formats_attr[] = { + &format_attr_event5.attr, + &format_attr_counter.attr, + &format_attr_match.attr, + &format_attr_mask.attr, + NULL, +}; + +static struct attribute_group nhmex_uncore_bbox_format_group = { + .name = "format", + .attrs = nhmex_uncore_bbox_formats_attr, +}; + +static struct intel_uncore_ops nhmex_uncore_bbox_ops = { + NHMEX_UNCORE_OPS_COMMON_INIT(), + .enable_event = nhmex_bbox_msr_enable_event, + .hw_config = nhmex_bbox_hw_config, + .get_constraint = uncore_get_constraint, + .put_constraint = uncore_put_constraint, +}; + +static struct intel_uncore_type nhmex_uncore_bbox = { + .name = "bbox", + .num_counters = 4, + .num_boxes = 2, + .perf_ctr_bits = 48, + .event_ctl = NHMEX_B0_MSR_PMON_CTL0, + .perf_ctr = NHMEX_B0_MSR_PMON_CTR0, + .event_mask = NHMEX_B_PMON_RAW_EVENT_MASK, + .box_ctl = NHMEX_B0_MSR_PMON_GLOBAL_CTL, + .msr_offset = NHMEX_B_MSR_OFFSET, + .pair_ctr_ctl = 1, + .num_shared_regs = 1, + .constraints = nhmex_uncore_bbox_constraints, + .ops = &nhmex_uncore_bbox_ops, + .format_group = &nhmex_uncore_bbox_format_group +}; + +static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + struct hw_perf_event_extra *reg2 = &hwc->branch_reg; + + /* only TO_R_PROG_EV event uses the match/mask register */ + if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) != + NHMEX_S_EVENT_TO_R_PROG_EV) + return 0; + + if (box->pmu->pmu_idx == 0) + reg1->reg = NHMEX_S0_MSR_MM_CFG; + else + reg1->reg = NHMEX_S1_MSR_MM_CFG; + reg1->idx = 0; + reg1->config = event->attr.config1; + reg2->config = event->attr.config2; + return 0; +} + +static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + struct hw_perf_event_extra *reg2 = &hwc->branch_reg; + + if (reg1->idx != EXTRA_REG_NONE) { + wrmsrl(reg1->reg, 0); + wrmsrl(reg1->reg + 1, reg1->config); + wrmsrl(reg1->reg + 2, reg2->config); + wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN); + } + wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22); +} + +static struct attribute *nhmex_uncore_sbox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh8.attr, + &format_attr_match.attr, + &format_attr_mask.attr, + NULL, +}; + +static struct attribute_group nhmex_uncore_sbox_format_group = { + .name = "format", + .attrs = nhmex_uncore_sbox_formats_attr, +}; + +static struct intel_uncore_ops nhmex_uncore_sbox_ops = { + NHMEX_UNCORE_OPS_COMMON_INIT(), + .enable_event = nhmex_sbox_msr_enable_event, + .hw_config = nhmex_sbox_hw_config, + .get_constraint = uncore_get_constraint, + .put_constraint = uncore_put_constraint, +}; + +static struct intel_uncore_type nhmex_uncore_sbox = { + .name = "sbox", + .num_counters = 4, + .num_boxes = 2, + .perf_ctr_bits = 48, + .event_ctl = NHMEX_S0_MSR_PMON_CTL0, + .perf_ctr = NHMEX_S0_MSR_PMON_CTR0, + .event_mask = NHMEX_PMON_RAW_EVENT_MASK, + .box_ctl = NHMEX_S0_MSR_PMON_GLOBAL_CTL, + .msr_offset = NHMEX_S_MSR_OFFSET, + .pair_ctr_ctl = 1, + .num_shared_regs = 1, + .ops = &nhmex_uncore_sbox_ops, + .format_group = &nhmex_uncore_sbox_format_group +}; + +enum { + EXTRA_REG_NHMEX_M_FILTER, + EXTRA_REG_NHMEX_M_DSP, + EXTRA_REG_NHMEX_M_ISS, + EXTRA_REG_NHMEX_M_MAP, + EXTRA_REG_NHMEX_M_MSC_THR, + EXTRA_REG_NHMEX_M_PGT, + EXTRA_REG_NHMEX_M_PLD, + EXTRA_REG_NHMEX_M_ZDP_CTL_FVC, +}; + +static struct extra_reg nhmex_uncore_mbox_extra_regs[] = { + MBOX_INC_SEL_EXTAR_REG(0x0, DSP), + MBOX_INC_SEL_EXTAR_REG(0x4, MSC_THR), + MBOX_INC_SEL_EXTAR_REG(0x5, MSC_THR), + MBOX_INC_SEL_EXTAR_REG(0x9, ISS), + /* event 0xa uses two extra registers */ + MBOX_INC_SEL_EXTAR_REG(0xa, ISS), + MBOX_INC_SEL_EXTAR_REG(0xa, PLD), + MBOX_INC_SEL_EXTAR_REG(0xb, PLD), + /* events 0xd ~ 0x10 use the same extra register */ + MBOX_INC_SEL_EXTAR_REG(0xd, ZDP_CTL_FVC), + MBOX_INC_SEL_EXTAR_REG(0xe, ZDP_CTL_FVC), + MBOX_INC_SEL_EXTAR_REG(0xf, ZDP_CTL_FVC), + MBOX_INC_SEL_EXTAR_REG(0x10, ZDP_CTL_FVC), + MBOX_INC_SEL_EXTAR_REG(0x16, PGT), + MBOX_SET_FLAG_SEL_EXTRA_REG(0x0, DSP), + MBOX_SET_FLAG_SEL_EXTRA_REG(0x1, ISS), + MBOX_SET_FLAG_SEL_EXTRA_REG(0x5, PGT), + MBOX_SET_FLAG_SEL_EXTRA_REG(0x6, MAP), + EVENT_EXTRA_END +}; + +/* Nehalem-EX or Westmere-EX ? */ +static bool uncore_nhmex; + +static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config) +{ + struct intel_uncore_extra_reg *er; + unsigned long flags; + bool ret = false; + u64 mask; + + if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) { + er = &box->shared_regs[idx]; + raw_spin_lock_irqsave(&er->lock, flags); + if (!atomic_read(&er->ref) || er->config == config) { + atomic_inc(&er->ref); + er->config = config; + ret = true; + } + raw_spin_unlock_irqrestore(&er->lock, flags); + + return ret; + } + /* + * The ZDP_CTL_FVC MSR has 4 fields which are used to control + * events 0xd ~ 0x10. Besides these 4 fields, there are additional + * fields which are shared. + */ + idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC; + if (WARN_ON_ONCE(idx >= 4)) + return false; + + /* mask of the shared fields */ + if (uncore_nhmex) + mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK; + else + mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK; + er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC]; + + raw_spin_lock_irqsave(&er->lock, flags); + /* add mask of the non-shared field if it's in use */ + if (__BITS_VALUE(atomic_read(&er->ref), idx, 8)) { + if (uncore_nhmex) + mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); + else + mask |= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); + } + + if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) { + atomic_add(1 << (idx * 8), &er->ref); + if (uncore_nhmex) + mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK | + NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); + else + mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK | + WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); + er->config &= ~mask; + er->config |= (config & mask); + ret = true; + } + raw_spin_unlock_irqrestore(&er->lock, flags); + + return ret; +} + +static void nhmex_mbox_put_shared_reg(struct intel_uncore_box *box, int idx) +{ + struct intel_uncore_extra_reg *er; + + if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) { + er = &box->shared_regs[idx]; + atomic_dec(&er->ref); + return; + } + + idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC; + er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC]; + atomic_sub(1 << (idx * 8), &er->ref); +} + +static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + u64 idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8); + u64 config = reg1->config; + + /* get the non-shared control bits and shift them */ + idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC; + if (uncore_nhmex) + config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); + else + config &= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx); + if (new_idx > orig_idx) { + idx = new_idx - orig_idx; + config <<= 3 * idx; + } else { + idx = orig_idx - new_idx; + config >>= 3 * idx; + } + + /* add the shared control bits back */ + if (uncore_nhmex) + config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config; + else + config |= WSMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config; + config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config; + if (modify) { + /* adjust the main event selector */ + if (new_idx > orig_idx) + hwc->config += idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT; + else + hwc->config -= idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT; + reg1->config = config; + reg1->idx = ~0xff | new_idx; + } + return config; +} + +static struct event_constraint * +nhmex_mbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + struct hw_perf_event_extra *reg2 = &event->hw.branch_reg; + int i, idx[2], alloc = 0; + u64 config1 = reg1->config; + + idx[0] = __BITS_VALUE(reg1->idx, 0, 8); + idx[1] = __BITS_VALUE(reg1->idx, 1, 8); +again: + for (i = 0; i < 2; i++) { + if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i))) + idx[i] = 0xff; + + if (idx[i] == 0xff) + continue; + + if (!nhmex_mbox_get_shared_reg(box, idx[i], + __BITS_VALUE(config1, i, 32))) + goto fail; + alloc |= (0x1 << i); + } + + /* for the match/mask registers */ + if (reg2->idx != EXTRA_REG_NONE && + (uncore_box_is_fake(box) || !reg2->alloc) && + !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config)) + goto fail; + + /* + * If it's a fake box -- as per validate_{group,event}() we + * shouldn't touch event state and we can avoid doing so + * since both will only call get_event_constraints() once + * on each event, this avoids the need for reg->alloc. + */ + if (!uncore_box_is_fake(box)) { + if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) + nhmex_mbox_alter_er(event, idx[0], true); + reg1->alloc |= alloc; + if (reg2->idx != EXTRA_REG_NONE) + reg2->alloc = 1; + } + return NULL; +fail: + if (idx[0] != 0xff && !(alloc & 0x1) && + idx[0] >= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) { + /* + * events 0xd ~ 0x10 are functional identical, but are + * controlled by different fields in the ZDP_CTL_FVC + * register. If we failed to take one field, try the + * rest 3 choices. + */ + BUG_ON(__BITS_VALUE(reg1->idx, 1, 8) != 0xff); + idx[0] -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC; + idx[0] = (idx[0] + 1) % 4; + idx[0] += EXTRA_REG_NHMEX_M_ZDP_CTL_FVC; + if (idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) { + config1 = nhmex_mbox_alter_er(event, idx[0], false); + goto again; + } + } + + if (alloc & 0x1) + nhmex_mbox_put_shared_reg(box, idx[0]); + if (alloc & 0x2) + nhmex_mbox_put_shared_reg(box, idx[1]); + return &uncore_constraint_empty; +} + +static void nhmex_mbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + struct hw_perf_event_extra *reg2 = &event->hw.branch_reg; + + if (uncore_box_is_fake(box)) + return; + + if (reg1->alloc & 0x1) + nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 0, 8)); + if (reg1->alloc & 0x2) + nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 1, 8)); + reg1->alloc = 0; + + if (reg2->alloc) { + nhmex_mbox_put_shared_reg(box, reg2->idx); + reg2->alloc = 0; + } +} + +static int nhmex_mbox_extra_reg_idx(struct extra_reg *er) +{ + if (er->idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) + return er->idx; + return er->idx + (er->event >> NHMEX_M_PMON_CTL_INC_SEL_SHIFT) - 0xd; +} + +static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) +{ + struct intel_uncore_type *type = box->pmu->type; + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + struct hw_perf_event_extra *reg2 = &event->hw.branch_reg; + struct extra_reg *er; + unsigned msr; + int reg_idx = 0; + /* + * The mbox events may require 2 extra MSRs at the most. But only + * the lower 32 bits in these MSRs are significant, so we can use + * config1 to pass two MSRs' config. + */ + for (er = nhmex_uncore_mbox_extra_regs; er->msr; er++) { + if (er->event != (event->hw.config & er->config_mask)) + continue; + if (event->attr.config1 & ~er->valid_mask) + return -EINVAL; + + msr = er->msr + type->msr_offset * box->pmu->pmu_idx; + if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff)) + return -EINVAL; + + /* always use the 32~63 bits to pass the PLD config */ + if (er->idx == EXTRA_REG_NHMEX_M_PLD) + reg_idx = 1; + else if (WARN_ON_ONCE(reg_idx > 0)) + return -EINVAL; + + reg1->idx &= ~(0xff << (reg_idx * 8)); + reg1->reg &= ~(0xffff << (reg_idx * 16)); + reg1->idx |= nhmex_mbox_extra_reg_idx(er) << (reg_idx * 8); + reg1->reg |= msr << (reg_idx * 16); + reg1->config = event->attr.config1; + reg_idx++; + } + /* + * The mbox only provides ability to perform address matching + * for the PLD events. + */ + if (reg_idx == 2) { + reg2->idx = EXTRA_REG_NHMEX_M_FILTER; + if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN) + reg2->config = event->attr.config2; + else + reg2->config = ~0ULL; + if (box->pmu->pmu_idx == 0) + reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG; + else + reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG; + } + return 0; +} + +static u64 nhmex_mbox_shared_reg_config(struct intel_uncore_box *box, int idx) +{ + struct intel_uncore_extra_reg *er; + unsigned long flags; + u64 config; + + if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) + return box->shared_regs[idx].config; + + er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC]; + raw_spin_lock_irqsave(&er->lock, flags); + config = er->config; + raw_spin_unlock_irqrestore(&er->lock, flags); + return config; +} + +static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + struct hw_perf_event_extra *reg2 = &hwc->branch_reg; + int idx; + + idx = __BITS_VALUE(reg1->idx, 0, 8); + if (idx != 0xff) + wrmsrl(__BITS_VALUE(reg1->reg, 0, 16), + nhmex_mbox_shared_reg_config(box, idx)); + idx = __BITS_VALUE(reg1->idx, 1, 8); + if (idx != 0xff) + wrmsrl(__BITS_VALUE(reg1->reg, 1, 16), + nhmex_mbox_shared_reg_config(box, idx)); + + if (reg2->idx != EXTRA_REG_NONE) { + wrmsrl(reg2->reg, 0); + if (reg2->config != ~0ULL) { + wrmsrl(reg2->reg + 1, + reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK); + wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK & + (reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT)); + wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN); + } + } + + wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0); +} + +DEFINE_UNCORE_FORMAT_ATTR(count_mode, count_mode, "config:2-3"); +DEFINE_UNCORE_FORMAT_ATTR(storage_mode, storage_mode, "config:4-5"); +DEFINE_UNCORE_FORMAT_ATTR(wrap_mode, wrap_mode, "config:6"); +DEFINE_UNCORE_FORMAT_ATTR(flag_mode, flag_mode, "config:7"); +DEFINE_UNCORE_FORMAT_ATTR(inc_sel, inc_sel, "config:9-13"); +DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel, set_flag_sel, "config:19-21"); +DEFINE_UNCORE_FORMAT_ATTR(filter_cfg_en, filter_cfg_en, "config2:63"); +DEFINE_UNCORE_FORMAT_ATTR(filter_match, filter_match, "config2:0-33"); +DEFINE_UNCORE_FORMAT_ATTR(filter_mask, filter_mask, "config2:34-61"); +DEFINE_UNCORE_FORMAT_ATTR(dsp, dsp, "config1:0-31"); +DEFINE_UNCORE_FORMAT_ATTR(thr, thr, "config1:0-31"); +DEFINE_UNCORE_FORMAT_ATTR(fvc, fvc, "config1:0-31"); +DEFINE_UNCORE_FORMAT_ATTR(pgt, pgt, "config1:0-31"); +DEFINE_UNCORE_FORMAT_ATTR(map, map, "config1:0-31"); +DEFINE_UNCORE_FORMAT_ATTR(iss, iss, "config1:0-31"); +DEFINE_UNCORE_FORMAT_ATTR(pld, pld, "config1:32-63"); + +static struct attribute *nhmex_uncore_mbox_formats_attr[] = { + &format_attr_count_mode.attr, + &format_attr_storage_mode.attr, + &format_attr_wrap_mode.attr, + &format_attr_flag_mode.attr, + &format_attr_inc_sel.attr, + &format_attr_set_flag_sel.attr, + &format_attr_filter_cfg_en.attr, + &format_attr_filter_match.attr, + &format_attr_filter_mask.attr, + &format_attr_dsp.attr, + &format_attr_thr.attr, + &format_attr_fvc.attr, + &format_attr_pgt.attr, + &format_attr_map.attr, + &format_attr_iss.attr, + &format_attr_pld.attr, + NULL, +}; + +static struct attribute_group nhmex_uncore_mbox_format_group = { + .name = "format", + .attrs = nhmex_uncore_mbox_formats_attr, +}; + +static struct uncore_event_desc nhmex_uncore_mbox_events[] = { + INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x2800"), + INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x2820"), + { /* end: all zeroes */ }, +}; + +static struct uncore_event_desc wsmex_uncore_mbox_events[] = { + INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x5000"), + INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x5040"), + { /* end: all zeroes */ }, +}; + +static struct intel_uncore_ops nhmex_uncore_mbox_ops = { + NHMEX_UNCORE_OPS_COMMON_INIT(), + .enable_event = nhmex_mbox_msr_enable_event, + .hw_config = nhmex_mbox_hw_config, + .get_constraint = nhmex_mbox_get_constraint, + .put_constraint = nhmex_mbox_put_constraint, +}; + +static struct intel_uncore_type nhmex_uncore_mbox = { + .name = "mbox", + .num_counters = 6, + .num_boxes = 2, + .perf_ctr_bits = 48, + .event_ctl = NHMEX_M0_MSR_PMU_CTL0, + .perf_ctr = NHMEX_M0_MSR_PMU_CNT0, + .event_mask = NHMEX_M_PMON_RAW_EVENT_MASK, + .box_ctl = NHMEX_M0_MSR_GLOBAL_CTL, + .msr_offset = NHMEX_M_MSR_OFFSET, + .pair_ctr_ctl = 1, + .num_shared_regs = 8, + .event_descs = nhmex_uncore_mbox_events, + .ops = &nhmex_uncore_mbox_ops, + .format_group = &nhmex_uncore_mbox_format_group, +}; + +static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + + /* adjust the main event selector and extra register index */ + if (reg1->idx % 2) { + reg1->idx--; + hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT; + } else { + reg1->idx++; + hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT; + } + + /* adjust extra register config */ + switch (reg1->idx % 6) { + case 2: + /* shift the 8~15 bits to the 0~7 bits */ + reg1->config >>= 8; + break; + case 3: + /* shift the 0~7 bits to the 8~15 bits */ + reg1->config <<= 8; + break; + }; +} + +/* + * Each rbox has 4 event set which monitor PQI port 0~3 or 4~7. + * An event set consists of 6 events, the 3rd and 4th events in + * an event set use the same extra register. So an event set uses + * 5 extra registers. + */ +static struct event_constraint * +nhmex_rbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + struct hw_perf_event_extra *reg2 = &hwc->branch_reg; + struct intel_uncore_extra_reg *er; + unsigned long flags; + int idx, er_idx; + u64 config1; + bool ok = false; + + if (!uncore_box_is_fake(box) && reg1->alloc) + return NULL; + + idx = reg1->idx % 6; + config1 = reg1->config; +again: + er_idx = idx; + /* the 3rd and 4th events use the same extra register */ + if (er_idx > 2) + er_idx--; + er_idx += (reg1->idx / 6) * 5; + + er = &box->shared_regs[er_idx]; + raw_spin_lock_irqsave(&er->lock, flags); + if (idx < 2) { + if (!atomic_read(&er->ref) || er->config == reg1->config) { + atomic_inc(&er->ref); + er->config = reg1->config; + ok = true; + } + } else if (idx == 2 || idx == 3) { + /* + * these two events use different fields in a extra register, + * the 0~7 bits and the 8~15 bits respectively. + */ + u64 mask = 0xff << ((idx - 2) * 8); + if (!__BITS_VALUE(atomic_read(&er->ref), idx - 2, 8) || + !((er->config ^ config1) & mask)) { + atomic_add(1 << ((idx - 2) * 8), &er->ref); + er->config &= ~mask; + er->config |= config1 & mask; + ok = true; + } + } else { + if (!atomic_read(&er->ref) || + (er->config == (hwc->config >> 32) && + er->config1 == reg1->config && + er->config2 == reg2->config)) { + atomic_inc(&er->ref); + er->config = (hwc->config >> 32); + er->config1 = reg1->config; + er->config2 = reg2->config; + ok = true; + } + } + raw_spin_unlock_irqrestore(&er->lock, flags); + + if (!ok) { + /* + * The Rbox events are always in pairs. The paired + * events are functional identical, but use different + * extra registers. If we failed to take an extra + * register, try the alternative. + */ + idx ^= 1; + if (idx != reg1->idx % 6) { + if (idx == 2) + config1 >>= 8; + else if (idx == 3) + config1 <<= 8; + goto again; + } + } else { + if (!uncore_box_is_fake(box)) { + if (idx != reg1->idx % 6) + nhmex_rbox_alter_er(box, event); + reg1->alloc = 1; + } + return NULL; + } + return &uncore_constraint_empty; +} + +static void nhmex_rbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event) +{ + struct intel_uncore_extra_reg *er; + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + int idx, er_idx; + + if (uncore_box_is_fake(box) || !reg1->alloc) + return; + + idx = reg1->idx % 6; + er_idx = idx; + if (er_idx > 2) + er_idx--; + er_idx += (reg1->idx / 6) * 5; + + er = &box->shared_regs[er_idx]; + if (idx == 2 || idx == 3) + atomic_sub(1 << ((idx - 2) * 8), &er->ref); + else + atomic_dec(&er->ref); + + reg1->alloc = 0; +} + +static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; + struct hw_perf_event_extra *reg2 = &event->hw.branch_reg; + int idx; + + idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >> + NHMEX_R_PMON_CTL_EV_SEL_SHIFT; + if (idx >= 0x18) + return -EINVAL; + + reg1->idx = idx; + reg1->config = event->attr.config1; + + switch (idx % 6) { + case 4: + case 5: + hwc->config |= event->attr.config & (~0ULL << 32); + reg2->config = event->attr.config2; + break; + }; + return 0; +} + +static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event_extra *reg1 = &hwc->extra_reg; + struct hw_perf_event_extra *reg2 = &hwc->branch_reg; + int idx, port; + + idx = reg1->idx; + port = idx / 6 + box->pmu->pmu_idx * 4; + + switch (idx % 6) { + case 0: + wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG0(port), reg1->config); + break; + case 1: + wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG1(port), reg1->config); + break; + case 2: + case 3: + wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port), + uncore_shared_reg_config(box, 2 + (idx / 6) * 5)); + break; + case 4: + wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port), + hwc->config >> 32); + wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(port), reg1->config); + wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MASK(port), reg2->config); + break; + case 5: + wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port), + hwc->config >> 32); + wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config); + wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config); + break; + }; + + wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 | + (hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK)); +} + +DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config:32-63"); +DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config1:0-63"); +DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63"); +DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15"); +DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31"); + +static struct attribute *nhmex_uncore_rbox_formats_attr[] = { + &format_attr_event5.attr, + &format_attr_xbr_mm_cfg.attr, + &format_attr_xbr_match.attr, + &format_attr_xbr_mask.attr, + &format_attr_qlx_cfg.attr, + &format_attr_iperf_cfg.attr, + NULL, +}; + +static struct attribute_group nhmex_uncore_rbox_format_group = { + .name = "format", + .attrs = nhmex_uncore_rbox_formats_attr, +}; + +static struct uncore_event_desc nhmex_uncore_rbox_events[] = { + INTEL_UNCORE_EVENT_DESC(qpi0_flit_send, "event=0x0,iperf_cfg=0x80000000"), + INTEL_UNCORE_EVENT_DESC(qpi1_filt_send, "event=0x6,iperf_cfg=0x80000000"), + INTEL_UNCORE_EVENT_DESC(qpi0_idle_filt, "event=0x0,iperf_cfg=0x40000000"), + INTEL_UNCORE_EVENT_DESC(qpi1_idle_filt, "event=0x6,iperf_cfg=0x40000000"), + INTEL_UNCORE_EVENT_DESC(qpi0_date_response, "event=0x0,iperf_cfg=0xc4"), + INTEL_UNCORE_EVENT_DESC(qpi1_date_response, "event=0x6,iperf_cfg=0xc4"), + { /* end: all zeroes */ }, +}; + +static struct intel_uncore_ops nhmex_uncore_rbox_ops = { + NHMEX_UNCORE_OPS_COMMON_INIT(), + .enable_event = nhmex_rbox_msr_enable_event, + .hw_config = nhmex_rbox_hw_config, + .get_constraint = nhmex_rbox_get_constraint, + .put_constraint = nhmex_rbox_put_constraint, +}; + +static struct intel_uncore_type nhmex_uncore_rbox = { + .name = "rbox", + .num_counters = 8, + .num_boxes = 2, + .perf_ctr_bits = 48, + .event_ctl = NHMEX_R_MSR_PMON_CTL0, + .perf_ctr = NHMEX_R_MSR_PMON_CNT0, + .event_mask = NHMEX_R_PMON_RAW_EVENT_MASK, + .box_ctl = NHMEX_R_MSR_GLOBAL_CTL, + .msr_offset = NHMEX_R_MSR_OFFSET, + .pair_ctr_ctl = 1, + .num_shared_regs = 20, + .event_descs = nhmex_uncore_rbox_events, + .ops = &nhmex_uncore_rbox_ops, + .format_group = &nhmex_uncore_rbox_format_group +}; + +static struct intel_uncore_type *nhmex_msr_uncores[] = { + &nhmex_uncore_ubox, + &nhmex_uncore_cbox, + &nhmex_uncore_bbox, + &nhmex_uncore_sbox, + &nhmex_uncore_mbox, + &nhmex_uncore_rbox, + &nhmex_uncore_wbox, + NULL, +}; + +void nhmex_uncore_cpu_init(void) +{ + if (boot_cpu_data.x86_model == 46) + uncore_nhmex = true; + else + nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events; + if (nhmex_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores) + nhmex_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores; + uncore_msr_uncores = nhmex_msr_uncores; +} +/* end of Nehalem-EX uncore support */ -- GitLab From 17a6034555c601331311d31beb395f6665056b3e Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Mon, 4 Aug 2014 13:29:11 +0200 Subject: [PATCH 0199/5088] perf/x86/uncore: Fix coccinelle warnings arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c:961:2-3: Unneeded semicolon arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c:1100:2-3: Unneeded semicolon arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c:1138:2-3: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Signed-off-by: Fengguang Wu Signed-off-by: Peter Zijlstra Cc: Yan, Zheng Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/n/tip-ovfvr4nbqjo7nzc16y2lpjy9@git.kernel.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c index 93b11a8f110d..2749965afed0 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c @@ -958,7 +958,7 @@ static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event /* shift the 0~7 bits to the 8~15 bits */ reg1->config <<= 8; break; - }; + } } /* @@ -1097,7 +1097,7 @@ static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event hwc->config |= event->attr.config & (~0ULL << 32); reg2->config = event->attr.config2; break; - }; + } return 0; } @@ -1135,7 +1135,7 @@ static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct per wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config); wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config); break; - }; + } wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 | (hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK)); -- GitLab From 36bbb2f2988a29cdc3f8e0c93478795934553454 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 31 Jul 2014 14:05:22 -0700 Subject: [PATCH 0200/5088] perf/x86: Use extended offcore mask on Haswell HSW-EP has a larger offcore mask than the client Haswell CPUs. It is the same mask as on Sandy/IvyBridge-EP. All of Haswell was using the client mask, so some bits were missing. On the client parts some bits were also missing compared to Sandy/IvyBridge, in particular the bits to match on a L4 cache hit. The Haswell core in both client and server incarnations accepts the same bits (but some are nops), so we can use the same mask. So use the snbep extended mask, which is a superset of the client and the server, for all of Haswell. This allows specifying a number of extra offcore events, like for example for HSW-EP. % perf stat -e cpu/event=0xb7,umask=0x1,offcore_rsp=0x3fffc00100,name=offcore_response_pf_l3_rfo_l3_miss_any_response/ true which were before. Signed-off-by: Andi Kleen Reviewed-by: eranian@google.com Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/r/1406840722-25416-1-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 38d1f6d024ff..89bc750efccb 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -2553,7 +2553,7 @@ __init int intel_pmu_init(void) x86_pmu.event_constraints = intel_hsw_event_constraints; x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints; - x86_pmu.extra_regs = intel_snb_extra_regs; + x86_pmu.extra_regs = intel_snbep_extra_regs; x86_pmu.pebs_aliases = intel_pebs_aliases_snb; /* all extra regs are per-cpu when HT is on */ x86_pmu.er_flags |= ERF_HAS_RSP_1; -- GitLab From e708d7ad80737496870fd0b6794704d063fb0cdc Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 4 Aug 2014 15:31:08 +0200 Subject: [PATCH 0201/5088] perf: Do poll_wait() before checking condition in perf_poll() One should first enqueue to the waitqueue and then check for the condition. If the condition gets true after mutex_unlock() but before poll_wait() then we lose it and would have wait for another wakeup. This has been like this since v2.6.31-rc1 commit c7138f37f9 ("perf_counter: fix perf_poll()"). Before that it was slightly worse. I guess we get enough wakeups so if we miss here one it doesn't really matter. It is still a bad example. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1407159068-1478-1-git-send-email-bigeasy@linutronix.de Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Signed-off-by: Ingo Molnar --- kernel/events/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index a25460559b4f..2d7363adf678 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3629,6 +3629,7 @@ static unsigned int perf_poll(struct file *file, poll_table *wait) struct ring_buffer *rb; unsigned int events = POLL_HUP; + poll_wait(file, &event->waitq, wait); /* * Pin the event->rb by taking event->mmap_mutex; otherwise * perf_event_set_output() can swizzle our rb and make us miss wakeups. @@ -3638,9 +3639,6 @@ static unsigned int perf_poll(struct file *file, poll_table *wait) if (rb) events = atomic_xchg(&rb->poll, 0); mutex_unlock(&event->mmap_mutex); - - poll_wait(file, &event->waitq, wait); - return events; } -- GitLab From 03de874aa76ac0adcf6f56ebf3de623d09a5dde3 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 7 Aug 2014 17:08:54 -0700 Subject: [PATCH 0202/5088] perf/x86: Fix :pp without LBR This fixes a side effect of Kan's earlier patch to probe the LBRs at boot time. Normally when the LBRs are disabled cycles:pp is disabled too. So for example cycles:pp doesn't work. However this is not needed with PEBSv2 and later (Haswell) because it does not need LBRs to correct the IP-off-by-one. So add an extra check for PEBSv2 that also allows :pp Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra Cc: kan.liang@intel.com Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/r/1407456534-15747-1-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 2879ecdaac43..0646d3b63b9d 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -387,7 +387,7 @@ int x86_pmu_hw_config(struct perf_event *event) precise++; /* Support for IP fixup */ - if (x86_pmu.lbr_nr) + if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 2) precise++; } -- GitLab From 86a04461a99fb857bd7d7f87b234cae27df07f8a Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 11 Aug 2014 21:27:10 +0200 Subject: [PATCH 0203/5088] perf/x86: Revamp PEBS event selection The basic idea is that it does not make sense to list all PEBS events individually. The list is very long, sometimes outdated and the hardware doesn't need it. If an event does not support PEBS it will just not count, there is no security issue. We need to only list events that something special, like supporting load or store addresses. This vastly simplifies the PEBS event selection. It also speeds up the scheduling because the scheduler doesn't have to walk as many constraints. Bugs fixed: - We do not allow setting forbidden flags with PEBS anymore (SDM 18.9.4), except for the special cycle event. This is done using a new constraint macro that also matches on the event flags. - Correct DataLA and load/store/na flags reporting on Haswell [Requires a followon patch] - We did not allow all PEBS events on Haswell: We were missing some valid subevents in d1-d2 (MEM_LOAD_UOPS_RETIRED.*, MEM_LOAD_UOPS_RETIRED_L3_HIT_RETIRED.*) This includes the changes proposed by Stephane earlier and obsoletes his patchkit (except for some changes on pre Sandy Bridge/Silvermont CPUs) I only did Sandy Bridge and Silvermont and later so far, mostly because these are the parts I could directly confirm the hardware behavior with hardware architects. Also I do not believe the older CPUs have any missing events in their PEBS list, so there's no pressing need to change them. I did not implement the flag proposed by Peter to allow setting forbidden flags. If really needed this could be implemented on to of this patch. v2: Fix broken store events on SNB/IVB (Stephane Eranian) v3: More fixes. Rename some arguments (Stephane Eranian) v4: List most Haswell events individually again to report memory operation type correctly. Add new flags to describe load/store/na for datala. Update description. Signed-off-by: Andi Kleen Reviewed-by: Stephane Eranian Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1407785233-32193-2-git-send-email-eranian@google.com Cc: Arnaldo Carvalho de Melo Cc: Kan Liang Cc: Linus Torvalds Cc: Maria Dimakopoulou Cc: Mark Davies Cc: Paul Mackerras Cc: Stephane Eranian Cc: Yan, Zheng Signed-off-by: Ingo Molnar --- arch/x86/include/asm/perf_event.h | 8 ++ arch/x86/kernel/cpu/perf_event.h | 48 ++++++++-- arch/x86/kernel/cpu/perf_event_intel_ds.c | 107 +++++++--------------- 3 files changed, 85 insertions(+), 78 deletions(-) diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 8249df45d2f2..8dfc9fd094a3 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -51,6 +51,14 @@ ARCH_PERFMON_EVENTSEL_EDGE | \ ARCH_PERFMON_EVENTSEL_INV | \ ARCH_PERFMON_EVENTSEL_CMASK) +#define X86_ALL_EVENT_FLAGS \ + (ARCH_PERFMON_EVENTSEL_EDGE | \ + ARCH_PERFMON_EVENTSEL_INV | \ + ARCH_PERFMON_EVENTSEL_CMASK | \ + ARCH_PERFMON_EVENTSEL_ANY | \ + ARCH_PERFMON_EVENTSEL_PIN_CONTROL | \ + HSW_IN_TX | \ + HSW_IN_TX_CHECKPOINTED) #define AMD64_RAW_EVENT_MASK \ (X86_RAW_EVENT_MASK | \ AMD64_EVENTSEL_EVENT) diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 8ade93111e03..fc5eb390b368 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -67,8 +67,10 @@ struct event_constraint { */ #define PERF_X86_EVENT_PEBS_LDLAT 0x1 /* ld+ldlat data address sampling */ #define PERF_X86_EVENT_PEBS_ST 0x2 /* st data address sampling */ -#define PERF_X86_EVENT_PEBS_ST_HSW 0x4 /* haswell style st data sampling */ +#define PERF_X86_EVENT_PEBS_ST_HSW 0x4 /* haswell style datala, store */ #define PERF_X86_EVENT_COMMITTED 0x8 /* event passed commit_txn */ +#define PERF_X86_EVENT_PEBS_LD_HSW 0x10 /* haswell style datala, load */ +#define PERF_X86_EVENT_PEBS_NA_HSW 0x20 /* haswell style datala, unknown */ struct amd_nb { int nb_id; /* NorthBridge id */ @@ -252,18 +254,52 @@ struct cpu_hw_events { EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK) #define INTEL_PLD_CONSTRAINT(c, n) \ - __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \ + __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT) #define INTEL_PST_CONSTRAINT(c, n) \ - __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \ + __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST) -/* DataLA version of store sampling without extra enable bit. */ -#define INTEL_PST_HSW_CONSTRAINT(c, n) \ - __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \ +/* Event constraint, but match on all event flags too. */ +#define INTEL_FLAGS_EVENT_CONSTRAINT(c, n) \ + EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS) + +/* Check only flags, but allow all event/umask */ +#define INTEL_ALL_EVENT_CONSTRAINT(code, n) \ + EVENT_CONSTRAINT(code, n, X86_ALL_EVENT_FLAGS) + +/* Check flags and event code, and set the HSW store flag */ +#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_ST(code, n) \ + __EVENT_CONSTRAINT(code, n, \ + ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \ + HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW) + +/* Check flags and event code, and set the HSW load flag */ +#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(code, n) \ + __EVENT_CONSTRAINT(code, n, \ + ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \ + HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW) + +/* Check flags and event code/umask, and set the HSW store flag */ +#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(code, n) \ + __EVENT_CONSTRAINT(code, n, \ + INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW) +/* Check flags and event code/umask, and set the HSW load flag */ +#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(code, n) \ + __EVENT_CONSTRAINT(code, n, \ + INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ + HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW) + +/* Check flags and event code/umask, and set the HSW N/A flag */ +#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(code, n) \ + __EVENT_CONSTRAINT(code, n, \ + INTEL_ARCH_EVENT_MASK|INTEL_ARCH_EVENT_MASK, \ + HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_NA_HSW) + + /* * We define the end marker as having a weight of -1 * to enable blacklisting of events using a counter bitmask diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 696ade311ded..aca77e99e676 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -569,28 +569,10 @@ struct event_constraint intel_atom_pebs_event_constraints[] = { }; struct event_constraint intel_slm_pebs_event_constraints[] = { - INTEL_UEVENT_CONSTRAINT(0x0103, 0x1), /* REHABQ.LD_BLOCK_ST_FORWARD_PS */ - INTEL_UEVENT_CONSTRAINT(0x0803, 0x1), /* REHABQ.LD_SPLITS_PS */ - INTEL_UEVENT_CONSTRAINT(0x0204, 0x1), /* MEM_UOPS_RETIRED.L2_HIT_LOADS_PS */ - INTEL_UEVENT_CONSTRAINT(0x0404, 0x1), /* MEM_UOPS_RETIRED.L2_MISS_LOADS_PS */ - INTEL_UEVENT_CONSTRAINT(0x0804, 0x1), /* MEM_UOPS_RETIRED.DTLB_MISS_LOADS_PS */ - INTEL_UEVENT_CONSTRAINT(0x2004, 0x1), /* MEM_UOPS_RETIRED.HITM_PS */ - INTEL_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY_PS */ - INTEL_UEVENT_CONSTRAINT(0x00c4, 0x1), /* BR_INST_RETIRED.ALL_BRANCHES_PS */ - INTEL_UEVENT_CONSTRAINT(0x7ec4, 0x1), /* BR_INST_RETIRED.JCC_PS */ - INTEL_UEVENT_CONSTRAINT(0xbfc4, 0x1), /* BR_INST_RETIRED.FAR_BRANCH_PS */ - INTEL_UEVENT_CONSTRAINT(0xebc4, 0x1), /* BR_INST_RETIRED.NON_RETURN_IND_PS */ - INTEL_UEVENT_CONSTRAINT(0xf7c4, 0x1), /* BR_INST_RETIRED.RETURN_PS */ - INTEL_UEVENT_CONSTRAINT(0xf9c4, 0x1), /* BR_INST_RETIRED.CALL_PS */ - INTEL_UEVENT_CONSTRAINT(0xfbc4, 0x1), /* BR_INST_RETIRED.IND_CALL_PS */ - INTEL_UEVENT_CONSTRAINT(0xfdc4, 0x1), /* BR_INST_RETIRED.REL_CALL_PS */ - INTEL_UEVENT_CONSTRAINT(0xfec4, 0x1), /* BR_INST_RETIRED.TAKEN_JCC_PS */ - INTEL_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_MISP_RETIRED.ALL_BRANCHES_PS */ - INTEL_UEVENT_CONSTRAINT(0x7ec5, 0x1), /* BR_INST_MISP_RETIRED.JCC_PS */ - INTEL_UEVENT_CONSTRAINT(0xebc5, 0x1), /* BR_INST_MISP_RETIRED.NON_RETURN_IND_PS */ - INTEL_UEVENT_CONSTRAINT(0xf7c5, 0x1), /* BR_INST_MISP_RETIRED.RETURN_PS */ - INTEL_UEVENT_CONSTRAINT(0xfbc5, 0x1), /* BR_INST_MISP_RETIRED.IND_CALL_PS */ - INTEL_UEVENT_CONSTRAINT(0xfec5, 0x1), /* BR_INST_MISP_RETIRED.TAKEN_JCC_PS */ + /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ + INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), + /* Allow all events as PEBS with no flags */ + INTEL_ALL_EVENT_CONSTRAINT(0, 0x1), EVENT_CONSTRAINT_END }; @@ -626,68 +608,44 @@ struct event_constraint intel_westmere_pebs_event_constraints[] = { struct event_constraint intel_snb_pebs_event_constraints[] = { INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ - INTEL_UEVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */ - INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */ - INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */ INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */ INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */ - INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_UOP_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xd3, 0xf), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ - INTEL_UEVENT_CONSTRAINT(0x02d4, 0xf), /* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */ + /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ + INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), + /* Allow all events as PEBS with no flags */ + INTEL_ALL_EVENT_CONSTRAINT(0, 0xf), EVENT_CONSTRAINT_END }; struct event_constraint intel_ivb_pebs_event_constraints[] = { INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ - INTEL_UEVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */ - INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */ - INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */ INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */ INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */ - INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_UOP_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ - INTEL_EVENT_CONSTRAINT(0xd3, 0xf), /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */ + /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ + INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), + /* Allow all events as PEBS with no flags */ + INTEL_ALL_EVENT_CONSTRAINT(0, 0xf), EVENT_CONSTRAINT_END }; struct event_constraint intel_hsw_pebs_event_constraints[] = { INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ - INTEL_PST_HSW_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */ - INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */ - INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */ - INTEL_UEVENT_CONSTRAINT(0x01c5, 0xf), /* BR_MISP_RETIRED.CONDITIONAL */ - INTEL_UEVENT_CONSTRAINT(0x04c5, 0xf), /* BR_MISP_RETIRED.ALL_BRANCHES */ - INTEL_UEVENT_CONSTRAINT(0x20c5, 0xf), /* BR_MISP_RETIRED.NEAR_TAKEN */ - INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.* */ - /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */ - INTEL_UEVENT_CONSTRAINT(0x11d0, 0xf), - /* MEM_UOPS_RETIRED.STLB_MISS_STORES */ - INTEL_UEVENT_CONSTRAINT(0x12d0, 0xf), - INTEL_UEVENT_CONSTRAINT(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */ - INTEL_UEVENT_CONSTRAINT(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */ - /* MEM_UOPS_RETIRED.SPLIT_STORES */ - INTEL_UEVENT_CONSTRAINT(0x42d0, 0xf), - INTEL_UEVENT_CONSTRAINT(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */ - INTEL_PST_HSW_CONSTRAINT(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */ - INTEL_UEVENT_CONSTRAINT(0x01d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L1_HIT */ - INTEL_UEVENT_CONSTRAINT(0x02d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L2_HIT */ - INTEL_UEVENT_CONSTRAINT(0x04d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L3_HIT */ - /* MEM_LOAD_UOPS_RETIRED.HIT_LFB */ - INTEL_UEVENT_CONSTRAINT(0x40d1, 0xf), - /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS */ - INTEL_UEVENT_CONSTRAINT(0x01d2, 0xf), - /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT */ - INTEL_UEVENT_CONSTRAINT(0x02d2, 0xf), - /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM */ - INTEL_UEVENT_CONSTRAINT(0x01d3, 0xf), - INTEL_UEVENT_CONSTRAINT(0x04c8, 0xf), /* HLE_RETIRED.Abort */ - INTEL_UEVENT_CONSTRAINT(0x04c9, 0xf), /* RTM_RETIRED.Abort */ - + INTEL_PLD_CONSTRAINT(0x01cd, 0xf), /* MEM_TRANS_RETIRED.* */ + /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */ + INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf), + INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */ + INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */ + INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */ + INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */ + INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */ + INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_STORES */ + INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x42d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_STORES */ + INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */ + INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */ + INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd2, 0xf), /* MEM_LOAD_UOPS_L3_HIT_RETIRED.* */ + INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd3, 0xf), /* MEM_LOAD_UOPS_L3_MISS_RETIRED.* */ + /* Allow all events as PEBS with no flags */ + INTEL_ALL_EVENT_CONSTRAINT(0, 0xf), EVENT_CONSTRAINT_END }; @@ -880,7 +838,9 @@ static void __intel_pmu_pebs_event(struct perf_event *event, fll = event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT; fst = event->hw.flags & (PERF_X86_EVENT_PEBS_ST | - PERF_X86_EVENT_PEBS_ST_HSW); + PERF_X86_EVENT_PEBS_ST_HSW | + PERF_X86_EVENT_PEBS_LD_HSW | + PERF_X86_EVENT_PEBS_NA_HSW); perf_sample_data_init(&data, 0, event->hw.last_period); @@ -903,7 +863,10 @@ static void __intel_pmu_pebs_event(struct perf_event *event, if (sample_type & PERF_SAMPLE_DATA_SRC) { if (fll) data.data_src.val = load_latency_data(pebs->dse); - else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) + else if (event->hw.flags & + (PERF_X86_EVENT_PEBS_ST_HSW| + PERF_X86_EVENT_PEBS_LD_HSW| + PERF_X86_EVENT_PEBS_NA_HSW)) data.data_src.val = precise_store_data_hsw(event, pebs->dse); else -- GitLab From f3908b8cfb65ab6e78ac84df3b864eb22d5b6d9e Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 11 Aug 2014 21:27:11 +0200 Subject: [PATCH 0204/5088] perf/x86: Don't mark DataLA addresses as store Haswell supports reporting the data address for a range of PEBS events, including: UOPS_RETIRED.ALL MEM_UOPS_RETIRED.STLB_MISS_LOADS MEM_UOPS_RETIRED.STLB_MISS_STORES MEM_UOPS_RETIRED.LOCK_LOADS MEM_UOPS_RETIRED.SPLIT_LOADS MEM_UOPS_RETIRED.SPLIT_STORES MEM_UOPS_RETIRED.ALL_LOADS MEM_UOPS_RETIRED.ALL_STORES MEM_LOAD_UOPS_RETIRED.L1_HIT MEM_LOAD_UOPS_RETIRED.L2_HIT MEM_LOAD_UOPS_RETIRED.L3_HIT MEM_LOAD_UOPS_RETIRED.L1_MISS MEM_LOAD_UOPS_RETIRED.L2_MISS MEM_LOAD_UOPS_RETIRED.L3_MISS MEM_LOAD_UOPS_RETIRED.HIT_LFB MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_MISS MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HITM MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_NONE MEM_LOAD_UOPS_L3_MISS_RETIRED.LOCAL_DRAM This facility was already enabled earlier with the original Haswell perf changes. However these addresses were always reports as stores by perf, which is wrong, as they could be loads too. The hardware does not distinguish loads and stores for these instructions, so there's no (cheap) way for the profiler to find out. Change the type to PERF_MEM_OP_NA instead. Signed-off-by: Andi Kleen Reviewed-by: Stephane Eranian Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/r/1407785233-32193-3-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_ds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index aca77e99e676..a9b60f32064f 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -114,7 +114,7 @@ static u64 precise_store_data_hsw(struct perf_event *event, u64 status) u64 cfg = event->hw.config & INTEL_ARCH_EVENT_MASK; dse.val = 0; - dse.mem_op = PERF_MEM_OP_STORE; + dse.mem_op = PERF_MEM_OP_NA; dse.mem_lvl = PERF_MEM_LVL_NA; /* -- GitLab From 770eee1fd38c70a009b321f5dbe64358f42511fd Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 11 Aug 2014 21:27:12 +0200 Subject: [PATCH 0205/5088] perf/x86: Fix data source encoding issues for load latency/precise store This patch fixes issues introuduce by Andi's previous patch 'Revamp PEBS' series. This patch fixes the following: - precise_store_data_hsw() encode the mem op type whenever we can - precise_store_data_hsw set the default data source correctly - 0 is not a valid init value for data source. Define PERF_MEM_NA as the default value This bug was actually introduced by commit 722e76e60f2775c21b087ff12c5e678cf0ebcaaf Author: Stephane Eranian Date: Thu May 15 17:56:44 2014 +0200 fix Haswell precise store data source encoding Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1407785233-32193-4-git-send-email-eranian@google.com Cc: Arnaldo Carvalho de Melo Cc: ak@linux.intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_ds.c | 11 +++++++---- include/linux/perf_event.h | 9 ++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index a9b60f32064f..67919ce0f76a 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -113,9 +113,12 @@ static u64 precise_store_data_hsw(struct perf_event *event, u64 status) union perf_mem_data_src dse; u64 cfg = event->hw.config & INTEL_ARCH_EVENT_MASK; - dse.val = 0; - dse.mem_op = PERF_MEM_OP_NA; - dse.mem_lvl = PERF_MEM_LVL_NA; + dse.val = PERF_MEM_NA; + + if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) + dse.mem_op = PERF_MEM_OP_STORE; + else if (event->hw.flags & PERF_X86_EVENT_PEBS_LD_HSW) + dse.mem_op = PERF_MEM_OP_LOAD; /* * L1 info only valid for following events: @@ -126,7 +129,7 @@ static u64 precise_store_data_hsw(struct perf_event *event, u64 status) * MEM_UOPS_RETIRED.ALL_STORES */ if (cfg != 0x12d0 && cfg != 0x22d0 && cfg != 0x42d0 && cfg != 0x82d0) - return dse.mem_lvl; + return dse.val; if (status & 1) dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT; diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ef5b62bdb103..f0a1036b1911 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -608,6 +608,13 @@ struct perf_sample_data { u64 txn; }; +/* default value for data source */ +#define PERF_MEM_NA (PERF_MEM_S(OP, NA) |\ + PERF_MEM_S(LVL, NA) |\ + PERF_MEM_S(SNOOP, NA) |\ + PERF_MEM_S(LOCK, NA) |\ + PERF_MEM_S(TLB, NA)) + static inline void perf_sample_data_init(struct perf_sample_data *data, u64 addr, u64 period) { @@ -620,7 +627,7 @@ static inline void perf_sample_data_init(struct perf_sample_data *data, data->regs_user.regs = NULL; data->stack_user_size = 0; data->weight = 0; - data->data_src.val = 0; + data->data_src.val = PERF_MEM_NA; data->txn = 0; } -- GitLab From c8aab2e04ac9f442a07abeaf49ddd1703c608f47 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 11 Aug 2014 21:27:13 +0200 Subject: [PATCH 0206/5088] perf/x86: Clean up __intel_pmu_pebs_event() code This patch makes the code more readable. It also renames precise_store_data_hsw() to precise_datala_hsw() because the function is called for both loads and stores on HSW. The patch also gets rid of the hardcoded store events codes in that same function. Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1407785233-32193-5-git-send-email-eranian@google.com Cc: ak@linux.intel.com Cc: Arnaldo Carvalho de Melo Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_ds.c | 81 +++++++++++------------ 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 67919ce0f76a..9dc419991772 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -108,10 +108,9 @@ static u64 precise_store_data(u64 status) return val; } -static u64 precise_store_data_hsw(struct perf_event *event, u64 status) +static u64 precise_datala_hsw(struct perf_event *event, u64 status) { union perf_mem_data_src dse; - u64 cfg = event->hw.config & INTEL_ARCH_EVENT_MASK; dse.val = PERF_MEM_NA; @@ -128,15 +127,12 @@ static u64 precise_store_data_hsw(struct perf_event *event, u64 status) * MEM_UOPS_RETIRED.SPLIT_STORES * MEM_UOPS_RETIRED.ALL_STORES */ - if (cfg != 0x12d0 && cfg != 0x22d0 && cfg != 0x42d0 && cfg != 0x82d0) - return dse.val; - - if (status & 1) - dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT; - else - dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS; - - /* Nothing else supported. Sorry. */ + if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) { + if (status & 1) + dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT; + else + dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS; + } return dse.val; } @@ -825,6 +821,10 @@ static inline u64 intel_hsw_transaction(struct pebs_record_hsw *pebs) static void __intel_pmu_pebs_event(struct perf_event *event, struct pt_regs *iregs, void *__pebs) { +#define PERF_X86_EVENT_PEBS_HSW_PREC \ + (PERF_X86_EVENT_PEBS_ST_HSW | \ + PERF_X86_EVENT_PEBS_LD_HSW | \ + PERF_X86_EVENT_PEBS_NA_HSW) /* * We cast to the biggest pebs_record but are careful not to * unconditionally access the 'extra' entries. @@ -834,47 +834,40 @@ static void __intel_pmu_pebs_event(struct perf_event *event, struct perf_sample_data data; struct pt_regs regs; u64 sample_type; - int fll, fst; + int fll, fst, dsrc; + int fl = event->hw.flags; if (!intel_pmu_save_and_restart(event)) return; - fll = event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT; - fst = event->hw.flags & (PERF_X86_EVENT_PEBS_ST | - PERF_X86_EVENT_PEBS_ST_HSW | - PERF_X86_EVENT_PEBS_LD_HSW | - PERF_X86_EVENT_PEBS_NA_HSW); + sample_type = event->attr.sample_type; + dsrc = sample_type & PERF_SAMPLE_DATA_SRC; + + fll = fl & PERF_X86_EVENT_PEBS_LDLAT; + fst = fl & (PERF_X86_EVENT_PEBS_ST | PERF_X86_EVENT_PEBS_HSW_PREC); perf_sample_data_init(&data, 0, event->hw.last_period); data.period = event->hw.last_period; - sample_type = event->attr.sample_type; /* - * if PEBS-LL or PreciseStore + * Use latency for weight (only avail with PEBS-LL) */ - if (fll || fst) { - /* - * Use latency for weight (only avail with PEBS-LL) - */ - if (fll && (sample_type & PERF_SAMPLE_WEIGHT)) - data.weight = pebs->lat; - - /* - * data.data_src encodes the data source - */ - if (sample_type & PERF_SAMPLE_DATA_SRC) { - if (fll) - data.data_src.val = load_latency_data(pebs->dse); - else if (event->hw.flags & - (PERF_X86_EVENT_PEBS_ST_HSW| - PERF_X86_EVENT_PEBS_LD_HSW| - PERF_X86_EVENT_PEBS_NA_HSW)) - data.data_src.val = - precise_store_data_hsw(event, pebs->dse); - else - data.data_src.val = precise_store_data(pebs->dse); - } + if (fll && (sample_type & PERF_SAMPLE_WEIGHT)) + data.weight = pebs->lat; + + /* + * data.data_src encodes the data source + */ + if (dsrc) { + u64 val = PERF_MEM_NA; + if (fll) + val = load_latency_data(pebs->dse); + else if (fst && (fl & PERF_X86_EVENT_PEBS_HSW_PREC)) + val = precise_datala_hsw(event, pebs->dse); + else if (fst) + val = precise_store_data(pebs->dse); + data.data_src.val = val; } /* @@ -901,16 +894,16 @@ static void __intel_pmu_pebs_event(struct perf_event *event, else regs.flags &= ~PERF_EFLAGS_EXACT; - if ((event->attr.sample_type & PERF_SAMPLE_ADDR) && + if ((sample_type & PERF_SAMPLE_ADDR) && x86_pmu.intel_cap.pebs_format >= 1) data.addr = pebs->dla; if (x86_pmu.intel_cap.pebs_format >= 2) { /* Only set the TSX weight when no memory weight. */ - if ((event->attr.sample_type & PERF_SAMPLE_WEIGHT) && !fll) + if ((sample_type & PERF_SAMPLE_WEIGHT) && !fll) data.weight = intel_hsw_weight(pebs); - if (event->attr.sample_type & PERF_SAMPLE_TRANSACTION) + if (sample_type & PERF_SAMPLE_TRANSACTION) data.txn = intel_hsw_transaction(pebs); } -- GitLab From 85a16ef66cc8a053de80aadf13722a2c1254d346 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 12 Aug 2014 08:00:31 +0200 Subject: [PATCH 0207/5088] perf/x86/uncore: Export basic memory events for IVT IMC PMU This patch exposes two basic events for Ivytown IMC uncore PMU: - cas_count_read: number of full-cache line reads to memory controller - cas_count_write: number of full-cache line writes to memory controller Those events use the same encoding as for SNB-EP, so reuse the same event table. See specification in: http://www.intel.com/content/dam/www/public/us/en/documents/manuals/xeon-e5-2600-v2-uncore-manual.pdf By aggregating all the read and write events from all the memory controllers of each processor socket, one can determine the total memory bandwidth utilization. Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20140812060031.GA25239@quad Cc: zheng.z.yan@intel.com Cc: ak@linux.intel.com Cc: Arnaldo Carvalho de Melo Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c index 30468f434e9e..00bd0485ed13 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c @@ -1422,6 +1422,7 @@ static struct intel_uncore_type ivt_uncore_imc = { .fixed_ctr_bits = 48, .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, + .event_descs = snbep_uncore_imc_events, IVT_UNCORE_PCI_COMMON_INIT(), }; -- GitLab From ddcd0973fe02aad3d4bdc59dd0f1db90f51105a9 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 12 Aug 2014 09:15:25 +0200 Subject: [PATCH 0208/5088] perf/x86/uncore: Rename IvyTown to IvyBridge-EP Keeping track of all the various CPU names is hard enough; adding extra silly names for no reason is just not helping. If we know the base arch name (IvyBridge) then we can do the client/server parts with the well known {,EP,EX} postfixes, no need to remember endless amounts of unrelated and pointless names for this. Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-8559jke61dsyr7d0i74iutli@git.kernel.org Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Stephane Eranian Cc: Yan, Zheng Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 8 +- arch/x86/kernel/cpu/perf_event_intel_uncore.h | 4 +- .../cpu/perf_event_intel_uncore_snbep.c | 340 +++++++++--------- 3 files changed, 176 insertions(+), 176 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index b1f84d9ccc48..4785ee8ac599 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -880,8 +880,8 @@ static int __init uncore_pci_init(void) case 45: /* Sandy Bridge-EP */ ret = snbep_uncore_pci_init(); break; - case 62: /* IvyTown */ - ret = ivt_uncore_pci_init(); + case 62: /* Ivy Bridge-EP */ + ret = ivbep_uncore_pci_init(); break; case 42: /* Sandy Bridge */ ret = snb_uncore_pci_init(); @@ -1187,8 +1187,8 @@ static int __init uncore_cpu_init(void) case 47: /* Westmere-EX aka. Xeon E7 */ nhmex_uncore_cpu_init(); break; - case 62: /* IvyTown */ - ivt_uncore_cpu_init(); + case 62: /* Ivy Bridge-EP */ + ivbep_uncore_cpu_init(); break; default: diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index b91559936d49..1d7e89416018 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -330,8 +330,8 @@ void nhm_uncore_cpu_init(void); /* perf_event_intel_uncore_snbep.c */ int snbep_uncore_pci_init(void); void snbep_uncore_cpu_init(void); -int ivt_uncore_pci_init(void); -void ivt_uncore_cpu_init(void); +int ivbep_uncore_pci_init(void); +void ivbep_uncore_cpu_init(void); /* perf_event_intel_uncore_nhmex.c */ void nhmex_uncore_cpu_init(void); diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c index 00bd0485ed13..d3e9c55d984a 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c @@ -111,43 +111,43 @@ #define SNBEP_PCU_MSR_CORE_C3_CTR 0x3fc #define SNBEP_PCU_MSR_CORE_C6_CTR 0x3fd -/* IVT event control */ -#define IVT_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \ +/* IVBEP event control */ +#define IVBEP_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \ SNBEP_PMON_BOX_CTL_RST_CTRS) -#define IVT_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \ +#define IVBEP_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \ SNBEP_PMON_CTL_UMASK_MASK | \ SNBEP_PMON_CTL_EDGE_DET | \ SNBEP_PMON_CTL_TRESH_MASK) -/* IVT Ubox */ -#define IVT_U_MSR_PMON_GLOBAL_CTL 0xc00 -#define IVT_U_PMON_GLOBAL_FRZ_ALL (1 << 31) -#define IVT_U_PMON_GLOBAL_UNFRZ_ALL (1 << 29) +/* IVBEP Ubox */ +#define IVBEP_U_MSR_PMON_GLOBAL_CTL 0xc00 +#define IVBEP_U_PMON_GLOBAL_FRZ_ALL (1 << 31) +#define IVBEP_U_PMON_GLOBAL_UNFRZ_ALL (1 << 29) -#define IVT_U_MSR_PMON_RAW_EVENT_MASK \ +#define IVBEP_U_MSR_PMON_RAW_EVENT_MASK \ (SNBEP_PMON_CTL_EV_SEL_MASK | \ SNBEP_PMON_CTL_UMASK_MASK | \ SNBEP_PMON_CTL_EDGE_DET | \ SNBEP_U_MSR_PMON_CTL_TRESH_MASK) -/* IVT Cbo */ -#define IVT_CBO_MSR_PMON_RAW_EVENT_MASK (IVT_PMON_RAW_EVENT_MASK | \ +/* IVBEP Cbo */ +#define IVBEP_CBO_MSR_PMON_RAW_EVENT_MASK (IVBEP_PMON_RAW_EVENT_MASK | \ SNBEP_CBO_PMON_CTL_TID_EN) -#define IVT_CB0_MSR_PMON_BOX_FILTER_TID (0x1fULL << 0) -#define IVT_CB0_MSR_PMON_BOX_FILTER_LINK (0xfULL << 5) -#define IVT_CB0_MSR_PMON_BOX_FILTER_STATE (0x3fULL << 17) -#define IVT_CB0_MSR_PMON_BOX_FILTER_NID (0xffffULL << 32) -#define IVT_CB0_MSR_PMON_BOX_FILTER_OPC (0x1ffULL << 52) -#define IVT_CB0_MSR_PMON_BOX_FILTER_C6 (0x1ULL << 61) -#define IVT_CB0_MSR_PMON_BOX_FILTER_NC (0x1ULL << 62) -#define IVT_CB0_MSR_PMON_BOX_FILTER_IOSC (0x1ULL << 63) - -/* IVT home agent */ -#define IVT_HA_PCI_PMON_CTL_Q_OCC_RST (1 << 16) -#define IVT_HA_PCI_PMON_RAW_EVENT_MASK \ - (IVT_PMON_RAW_EVENT_MASK | \ - IVT_HA_PCI_PMON_CTL_Q_OCC_RST) -/* IVT PCU */ -#define IVT_PCU_MSR_PMON_RAW_EVENT_MASK \ +#define IVBEP_CB0_MSR_PMON_BOX_FILTER_TID (0x1fULL << 0) +#define IVBEP_CB0_MSR_PMON_BOX_FILTER_LINK (0xfULL << 5) +#define IVBEP_CB0_MSR_PMON_BOX_FILTER_STATE (0x3fULL << 17) +#define IVBEP_CB0_MSR_PMON_BOX_FILTER_NID (0xffffULL << 32) +#define IVBEP_CB0_MSR_PMON_BOX_FILTER_OPC (0x1ffULL << 52) +#define IVBEP_CB0_MSR_PMON_BOX_FILTER_C6 (0x1ULL << 61) +#define IVBEP_CB0_MSR_PMON_BOX_FILTER_NC (0x1ULL << 62) +#define IVBEP_CB0_MSR_PMON_BOX_FILTER_IOSC (0x1ULL << 63) + +/* IVBEP home agent */ +#define IVBEP_HA_PCI_PMON_CTL_Q_OCC_RST (1 << 16) +#define IVBEP_HA_PCI_PMON_RAW_EVENT_MASK \ + (IVBEP_PMON_RAW_EVENT_MASK | \ + IVBEP_HA_PCI_PMON_CTL_Q_OCC_RST) +/* IVBEP PCU */ +#define IVBEP_PCU_MSR_PMON_RAW_EVENT_MASK \ (SNBEP_PMON_CTL_EV_SEL_MASK | \ SNBEP_PMON_CTL_EV_SEL_EXT | \ SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \ @@ -155,9 +155,9 @@ SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \ SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \ SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET) -/* IVT QPI */ -#define IVT_QPI_PCI_PMON_RAW_EVENT_MASK \ - (IVT_PMON_RAW_EVENT_MASK | \ +/* IVBEP QPI */ +#define IVBEP_QPI_PCI_PMON_RAW_EVENT_MASK \ + (IVBEP_PMON_RAW_EVENT_MASK | \ SNBEP_PMON_CTL_EV_SEL_EXT) #define __BITS_VALUE(x, i, n) ((typeof(x))(((x) >> ((i) * (n))) & \ @@ -1088,34 +1088,34 @@ int snbep_uncore_pci_init(void) /* end of Sandy Bridge-EP uncore support */ /* IvyTown uncore support */ -static void ivt_uncore_msr_init_box(struct intel_uncore_box *box) +static void ivbep_uncore_msr_init_box(struct intel_uncore_box *box) { unsigned msr = uncore_msr_box_ctl(box); if (msr) - wrmsrl(msr, IVT_PMON_BOX_CTL_INT); + wrmsrl(msr, IVBEP_PMON_BOX_CTL_INT); } -static void ivt_uncore_pci_init_box(struct intel_uncore_box *box) +static void ivbep_uncore_pci_init_box(struct intel_uncore_box *box) { struct pci_dev *pdev = box->pci_dev; - pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, IVT_PMON_BOX_CTL_INT); + pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, IVBEP_PMON_BOX_CTL_INT); } -#define IVT_UNCORE_MSR_OPS_COMMON_INIT() \ - .init_box = ivt_uncore_msr_init_box, \ +#define IVBEP_UNCORE_MSR_OPS_COMMON_INIT() \ + .init_box = ivbep_uncore_msr_init_box, \ .disable_box = snbep_uncore_msr_disable_box, \ .enable_box = snbep_uncore_msr_enable_box, \ .disable_event = snbep_uncore_msr_disable_event, \ .enable_event = snbep_uncore_msr_enable_event, \ .read_counter = uncore_msr_read_counter -static struct intel_uncore_ops ivt_uncore_msr_ops = { - IVT_UNCORE_MSR_OPS_COMMON_INIT(), +static struct intel_uncore_ops ivbep_uncore_msr_ops = { + IVBEP_UNCORE_MSR_OPS_COMMON_INIT(), }; -static struct intel_uncore_ops ivt_uncore_pci_ops = { - .init_box = ivt_uncore_pci_init_box, +static struct intel_uncore_ops ivbep_uncore_pci_ops = { + .init_box = ivbep_uncore_pci_init_box, .disable_box = snbep_uncore_pci_disable_box, .enable_box = snbep_uncore_pci_enable_box, .disable_event = snbep_uncore_pci_disable_event, @@ -1123,15 +1123,15 @@ static struct intel_uncore_ops ivt_uncore_pci_ops = { .read_counter = snbep_uncore_pci_read_counter, }; -#define IVT_UNCORE_PCI_COMMON_INIT() \ +#define IVBEP_UNCORE_PCI_COMMON_INIT() \ .perf_ctr = SNBEP_PCI_PMON_CTR0, \ .event_ctl = SNBEP_PCI_PMON_CTL0, \ - .event_mask = IVT_PMON_RAW_EVENT_MASK, \ + .event_mask = IVBEP_PMON_RAW_EVENT_MASK, \ .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ - .ops = &ivt_uncore_pci_ops, \ - .format_group = &ivt_uncore_format_group + .ops = &ivbep_uncore_pci_ops, \ + .format_group = &ivbep_uncore_format_group -static struct attribute *ivt_uncore_formats_attr[] = { +static struct attribute *ivbep_uncore_formats_attr[] = { &format_attr_event.attr, &format_attr_umask.attr, &format_attr_edge.attr, @@ -1140,7 +1140,7 @@ static struct attribute *ivt_uncore_formats_attr[] = { NULL, }; -static struct attribute *ivt_uncore_ubox_formats_attr[] = { +static struct attribute *ivbep_uncore_ubox_formats_attr[] = { &format_attr_event.attr, &format_attr_umask.attr, &format_attr_edge.attr, @@ -1149,7 +1149,7 @@ static struct attribute *ivt_uncore_ubox_formats_attr[] = { NULL, }; -static struct attribute *ivt_uncore_cbox_formats_attr[] = { +static struct attribute *ivbep_uncore_cbox_formats_attr[] = { &format_attr_event.attr, &format_attr_umask.attr, &format_attr_edge.attr, @@ -1163,7 +1163,7 @@ static struct attribute *ivt_uncore_cbox_formats_attr[] = { NULL, }; -static struct attribute *ivt_uncore_pcu_formats_attr[] = { +static struct attribute *ivbep_uncore_pcu_formats_attr[] = { &format_attr_event_ext.attr, &format_attr_occ_sel.attr, &format_attr_edge.attr, @@ -1177,7 +1177,7 @@ static struct attribute *ivt_uncore_pcu_formats_attr[] = { NULL, }; -static struct attribute *ivt_uncore_qpi_formats_attr[] = { +static struct attribute *ivbep_uncore_qpi_formats_attr[] = { &format_attr_event_ext.attr, &format_attr_umask.attr, &format_attr_edge.attr, @@ -1203,32 +1203,32 @@ static struct attribute *ivt_uncore_qpi_formats_attr[] = { NULL, }; -static struct attribute_group ivt_uncore_format_group = { +static struct attribute_group ivbep_uncore_format_group = { .name = "format", - .attrs = ivt_uncore_formats_attr, + .attrs = ivbep_uncore_formats_attr, }; -static struct attribute_group ivt_uncore_ubox_format_group = { +static struct attribute_group ivbep_uncore_ubox_format_group = { .name = "format", - .attrs = ivt_uncore_ubox_formats_attr, + .attrs = ivbep_uncore_ubox_formats_attr, }; -static struct attribute_group ivt_uncore_cbox_format_group = { +static struct attribute_group ivbep_uncore_cbox_format_group = { .name = "format", - .attrs = ivt_uncore_cbox_formats_attr, + .attrs = ivbep_uncore_cbox_formats_attr, }; -static struct attribute_group ivt_uncore_pcu_format_group = { +static struct attribute_group ivbep_uncore_pcu_format_group = { .name = "format", - .attrs = ivt_uncore_pcu_formats_attr, + .attrs = ivbep_uncore_pcu_formats_attr, }; -static struct attribute_group ivt_uncore_qpi_format_group = { +static struct attribute_group ivbep_uncore_qpi_format_group = { .name = "format", - .attrs = ivt_uncore_qpi_formats_attr, + .attrs = ivbep_uncore_qpi_formats_attr, }; -static struct intel_uncore_type ivt_uncore_ubox = { +static struct intel_uncore_type ivbep_uncore_ubox = { .name = "ubox", .num_counters = 2, .num_boxes = 1, @@ -1236,14 +1236,14 @@ static struct intel_uncore_type ivt_uncore_ubox = { .fixed_ctr_bits = 48, .perf_ctr = SNBEP_U_MSR_PMON_CTR0, .event_ctl = SNBEP_U_MSR_PMON_CTL0, - .event_mask = IVT_U_MSR_PMON_RAW_EVENT_MASK, + .event_mask = IVBEP_U_MSR_PMON_RAW_EVENT_MASK, .fixed_ctr = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR, .fixed_ctl = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL, - .ops = &ivt_uncore_msr_ops, - .format_group = &ivt_uncore_ubox_format_group, + .ops = &ivbep_uncore_msr_ops, + .format_group = &ivbep_uncore_ubox_format_group, }; -static struct extra_reg ivt_uncore_cbox_extra_regs[] = { +static struct extra_reg ivbep_uncore_cbox_extra_regs[] = { SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN, SNBEP_CBO_PMON_CTL_TID_EN, 0x1), SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2), @@ -1284,37 +1284,37 @@ static struct extra_reg ivt_uncore_cbox_extra_regs[] = { EVENT_EXTRA_END }; -static u64 ivt_cbox_filter_mask(int fields) +static u64 ivbep_cbox_filter_mask(int fields) { u64 mask = 0; if (fields & 0x1) - mask |= IVT_CB0_MSR_PMON_BOX_FILTER_TID; + mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_TID; if (fields & 0x2) - mask |= IVT_CB0_MSR_PMON_BOX_FILTER_LINK; + mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_LINK; if (fields & 0x4) - mask |= IVT_CB0_MSR_PMON_BOX_FILTER_STATE; + mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_STATE; if (fields & 0x8) - mask |= IVT_CB0_MSR_PMON_BOX_FILTER_NID; + mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_NID; if (fields & 0x10) - mask |= IVT_CB0_MSR_PMON_BOX_FILTER_OPC; + mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_OPC; return mask; } static struct event_constraint * -ivt_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) +ivbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event) { - return __snbep_cbox_get_constraint(box, event, ivt_cbox_filter_mask); + return __snbep_cbox_get_constraint(box, event, ivbep_cbox_filter_mask); } -static int ivt_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) +static int ivbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event) { struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; struct extra_reg *er; int idx = 0; - for (er = ivt_uncore_cbox_extra_regs; er->msr; er++) { + for (er = ivbep_uncore_cbox_extra_regs; er->msr; er++) { if (er->event != (event->hw.config & er->config_mask)) continue; idx |= er->idx; @@ -1323,13 +1323,13 @@ static int ivt_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *e if (idx) { reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER + SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx; - reg1->config = event->attr.config1 & ivt_cbox_filter_mask(idx); + reg1->config = event->attr.config1 & ivbep_cbox_filter_mask(idx); reg1->idx = idx; } return 0; } -static void ivt_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event) +static void ivbep_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; struct hw_perf_event_extra *reg1 = &hwc->extra_reg; @@ -1343,78 +1343,78 @@ static void ivt_cbox_enable_event(struct intel_uncore_box *box, struct perf_even wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); } -static struct intel_uncore_ops ivt_uncore_cbox_ops = { - .init_box = ivt_uncore_msr_init_box, +static struct intel_uncore_ops ivbep_uncore_cbox_ops = { + .init_box = ivbep_uncore_msr_init_box, .disable_box = snbep_uncore_msr_disable_box, .enable_box = snbep_uncore_msr_enable_box, .disable_event = snbep_uncore_msr_disable_event, - .enable_event = ivt_cbox_enable_event, + .enable_event = ivbep_cbox_enable_event, .read_counter = uncore_msr_read_counter, - .hw_config = ivt_cbox_hw_config, - .get_constraint = ivt_cbox_get_constraint, + .hw_config = ivbep_cbox_hw_config, + .get_constraint = ivbep_cbox_get_constraint, .put_constraint = snbep_cbox_put_constraint, }; -static struct intel_uncore_type ivt_uncore_cbox = { +static struct intel_uncore_type ivbep_uncore_cbox = { .name = "cbox", .num_counters = 4, .num_boxes = 15, .perf_ctr_bits = 44, .event_ctl = SNBEP_C0_MSR_PMON_CTL0, .perf_ctr = SNBEP_C0_MSR_PMON_CTR0, - .event_mask = IVT_CBO_MSR_PMON_RAW_EVENT_MASK, + .event_mask = IVBEP_CBO_MSR_PMON_RAW_EVENT_MASK, .box_ctl = SNBEP_C0_MSR_PMON_BOX_CTL, .msr_offset = SNBEP_CBO_MSR_OFFSET, .num_shared_regs = 1, .constraints = snbep_uncore_cbox_constraints, - .ops = &ivt_uncore_cbox_ops, - .format_group = &ivt_uncore_cbox_format_group, + .ops = &ivbep_uncore_cbox_ops, + .format_group = &ivbep_uncore_cbox_format_group, }; -static struct intel_uncore_ops ivt_uncore_pcu_ops = { - IVT_UNCORE_MSR_OPS_COMMON_INIT(), +static struct intel_uncore_ops ivbep_uncore_pcu_ops = { + IVBEP_UNCORE_MSR_OPS_COMMON_INIT(), .hw_config = snbep_pcu_hw_config, .get_constraint = snbep_pcu_get_constraint, .put_constraint = snbep_pcu_put_constraint, }; -static struct intel_uncore_type ivt_uncore_pcu = { +static struct intel_uncore_type ivbep_uncore_pcu = { .name = "pcu", .num_counters = 4, .num_boxes = 1, .perf_ctr_bits = 48, .perf_ctr = SNBEP_PCU_MSR_PMON_CTR0, .event_ctl = SNBEP_PCU_MSR_PMON_CTL0, - .event_mask = IVT_PCU_MSR_PMON_RAW_EVENT_MASK, + .event_mask = IVBEP_PCU_MSR_PMON_RAW_EVENT_MASK, .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL, .num_shared_regs = 1, - .ops = &ivt_uncore_pcu_ops, - .format_group = &ivt_uncore_pcu_format_group, + .ops = &ivbep_uncore_pcu_ops, + .format_group = &ivbep_uncore_pcu_format_group, }; -static struct intel_uncore_type *ivt_msr_uncores[] = { - &ivt_uncore_ubox, - &ivt_uncore_cbox, - &ivt_uncore_pcu, +static struct intel_uncore_type *ivbep_msr_uncores[] = { + &ivbep_uncore_ubox, + &ivbep_uncore_cbox, + &ivbep_uncore_pcu, NULL, }; -void ivt_uncore_cpu_init(void) +void ivbep_uncore_cpu_init(void) { - if (ivt_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores) - ivt_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores; - uncore_msr_uncores = ivt_msr_uncores; + if (ivbep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores) + ivbep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores; + uncore_msr_uncores = ivbep_msr_uncores; } -static struct intel_uncore_type ivt_uncore_ha = { +static struct intel_uncore_type ivbep_uncore_ha = { .name = "ha", .num_counters = 4, .num_boxes = 2, .perf_ctr_bits = 48, - IVT_UNCORE_PCI_COMMON_INIT(), + IVBEP_UNCORE_PCI_COMMON_INIT(), }; -static struct intel_uncore_type ivt_uncore_imc = { +static struct intel_uncore_type ivbep_uncore_imc = { .name = "imc", .num_counters = 4, .num_boxes = 8, @@ -1423,64 +1423,64 @@ static struct intel_uncore_type ivt_uncore_imc = { .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, .event_descs = snbep_uncore_imc_events, - IVT_UNCORE_PCI_COMMON_INIT(), + IVBEP_UNCORE_PCI_COMMON_INIT(), }; /* registers in IRP boxes are not properly aligned */ -static unsigned ivt_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4}; -static unsigned ivt_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0}; +static unsigned ivbep_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4}; +static unsigned ivbep_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0}; -static void ivt_uncore_irp_enable_event(struct intel_uncore_box *box, struct perf_event *event) +static void ivbep_uncore_irp_enable_event(struct intel_uncore_box *box, struct perf_event *event) { struct pci_dev *pdev = box->pci_dev; struct hw_perf_event *hwc = &event->hw; - pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx], + pci_write_config_dword(pdev, ivbep_uncore_irp_ctls[hwc->idx], hwc->config | SNBEP_PMON_CTL_EN); } -static void ivt_uncore_irp_disable_event(struct intel_uncore_box *box, struct perf_event *event) +static void ivbep_uncore_irp_disable_event(struct intel_uncore_box *box, struct perf_event *event) { struct pci_dev *pdev = box->pci_dev; struct hw_perf_event *hwc = &event->hw; - pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx], hwc->config); + pci_write_config_dword(pdev, ivbep_uncore_irp_ctls[hwc->idx], hwc->config); } -static u64 ivt_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event) +static u64 ivbep_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event) { struct pci_dev *pdev = box->pci_dev; struct hw_perf_event *hwc = &event->hw; u64 count = 0; - pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx], (u32 *)&count); - pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1); + pci_read_config_dword(pdev, ivbep_uncore_irp_ctrs[hwc->idx], (u32 *)&count); + pci_read_config_dword(pdev, ivbep_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1); return count; } -static struct intel_uncore_ops ivt_uncore_irp_ops = { - .init_box = ivt_uncore_pci_init_box, +static struct intel_uncore_ops ivbep_uncore_irp_ops = { + .init_box = ivbep_uncore_pci_init_box, .disable_box = snbep_uncore_pci_disable_box, .enable_box = snbep_uncore_pci_enable_box, - .disable_event = ivt_uncore_irp_disable_event, - .enable_event = ivt_uncore_irp_enable_event, - .read_counter = ivt_uncore_irp_read_counter, + .disable_event = ivbep_uncore_irp_disable_event, + .enable_event = ivbep_uncore_irp_enable_event, + .read_counter = ivbep_uncore_irp_read_counter, }; -static struct intel_uncore_type ivt_uncore_irp = { +static struct intel_uncore_type ivbep_uncore_irp = { .name = "irp", .num_counters = 4, .num_boxes = 1, .perf_ctr_bits = 48, - .event_mask = IVT_PMON_RAW_EVENT_MASK, + .event_mask = IVBEP_PMON_RAW_EVENT_MASK, .box_ctl = SNBEP_PCI_PMON_BOX_CTL, - .ops = &ivt_uncore_irp_ops, - .format_group = &ivt_uncore_format_group, + .ops = &ivbep_uncore_irp_ops, + .format_group = &ivbep_uncore_format_group, }; -static struct intel_uncore_ops ivt_uncore_qpi_ops = { - .init_box = ivt_uncore_pci_init_box, +static struct intel_uncore_ops ivbep_uncore_qpi_ops = { + .init_box = ivbep_uncore_pci_init_box, .disable_box = snbep_uncore_pci_disable_box, .enable_box = snbep_uncore_pci_enable_box, .disable_event = snbep_uncore_pci_disable_event, @@ -1491,129 +1491,129 @@ static struct intel_uncore_ops ivt_uncore_qpi_ops = { .put_constraint = uncore_put_constraint, }; -static struct intel_uncore_type ivt_uncore_qpi = { +static struct intel_uncore_type ivbep_uncore_qpi = { .name = "qpi", .num_counters = 4, .num_boxes = 3, .perf_ctr_bits = 48, .perf_ctr = SNBEP_PCI_PMON_CTR0, .event_ctl = SNBEP_PCI_PMON_CTL0, - .event_mask = IVT_QPI_PCI_PMON_RAW_EVENT_MASK, + .event_mask = IVBEP_QPI_PCI_PMON_RAW_EVENT_MASK, .box_ctl = SNBEP_PCI_PMON_BOX_CTL, .num_shared_regs = 1, - .ops = &ivt_uncore_qpi_ops, - .format_group = &ivt_uncore_qpi_format_group, + .ops = &ivbep_uncore_qpi_ops, + .format_group = &ivbep_uncore_qpi_format_group, }; -static struct intel_uncore_type ivt_uncore_r2pcie = { +static struct intel_uncore_type ivbep_uncore_r2pcie = { .name = "r2pcie", .num_counters = 4, .num_boxes = 1, .perf_ctr_bits = 44, .constraints = snbep_uncore_r2pcie_constraints, - IVT_UNCORE_PCI_COMMON_INIT(), + IVBEP_UNCORE_PCI_COMMON_INIT(), }; -static struct intel_uncore_type ivt_uncore_r3qpi = { +static struct intel_uncore_type ivbep_uncore_r3qpi = { .name = "r3qpi", .num_counters = 3, .num_boxes = 2, .perf_ctr_bits = 44, .constraints = snbep_uncore_r3qpi_constraints, - IVT_UNCORE_PCI_COMMON_INIT(), + IVBEP_UNCORE_PCI_COMMON_INIT(), }; enum { - IVT_PCI_UNCORE_HA, - IVT_PCI_UNCORE_IMC, - IVT_PCI_UNCORE_IRP, - IVT_PCI_UNCORE_QPI, - IVT_PCI_UNCORE_R2PCIE, - IVT_PCI_UNCORE_R3QPI, -}; - -static struct intel_uncore_type *ivt_pci_uncores[] = { - [IVT_PCI_UNCORE_HA] = &ivt_uncore_ha, - [IVT_PCI_UNCORE_IMC] = &ivt_uncore_imc, - [IVT_PCI_UNCORE_IRP] = &ivt_uncore_irp, - [IVT_PCI_UNCORE_QPI] = &ivt_uncore_qpi, - [IVT_PCI_UNCORE_R2PCIE] = &ivt_uncore_r2pcie, - [IVT_PCI_UNCORE_R3QPI] = &ivt_uncore_r3qpi, + IVBEP_PCI_UNCORE_HA, + IVBEP_PCI_UNCORE_IMC, + IVBEP_PCI_UNCORE_IRP, + IVBEP_PCI_UNCORE_QPI, + IVBEP_PCI_UNCORE_R2PCIE, + IVBEP_PCI_UNCORE_R3QPI, +}; + +static struct intel_uncore_type *ivbep_pci_uncores[] = { + [IVBEP_PCI_UNCORE_HA] = &ivbep_uncore_ha, + [IVBEP_PCI_UNCORE_IMC] = &ivbep_uncore_imc, + [IVBEP_PCI_UNCORE_IRP] = &ivbep_uncore_irp, + [IVBEP_PCI_UNCORE_QPI] = &ivbep_uncore_qpi, + [IVBEP_PCI_UNCORE_R2PCIE] = &ivbep_uncore_r2pcie, + [IVBEP_PCI_UNCORE_R3QPI] = &ivbep_uncore_r3qpi, NULL, }; -static DEFINE_PCI_DEVICE_TABLE(ivt_uncore_pci_ids) = { +static DEFINE_PCI_DEVICE_TABLE(ivbep_uncore_pci_ids) = { { /* Home Agent 0 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 0), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_HA, 0), }, { /* Home Agent 1 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 1), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_HA, 1), }, { /* MC0 Channel 0 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 0), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 0), }, { /* MC0 Channel 1 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 1), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 1), }, { /* MC0 Channel 3 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 2), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 2), }, { /* MC0 Channel 4 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 3), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 3), }, { /* MC1 Channel 0 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 4), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 4), }, { /* MC1 Channel 1 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 5), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 5), }, { /* MC1 Channel 3 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 6), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 6), }, { /* MC1 Channel 4 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 7), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 7), }, { /* IRP */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe39), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IRP, 0), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IRP, 0), }, { /* QPI0 Port 0 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 0), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 0), }, { /* QPI0 Port 1 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 1), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 1), }, { /* QPI1 Port 2 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 2), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 2), }, { /* R2PCIe */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R2PCIE, 0), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R2PCIE, 0), }, { /* R3QPI0 Link 0 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 0), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 0), }, { /* R3QPI0 Link 1 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 1), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 1), }, { /* R3QPI1 Link 2 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e), - .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 2), + .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 2), }, { /* QPI Port 0 filter */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe86), @@ -1628,18 +1628,18 @@ static DEFINE_PCI_DEVICE_TABLE(ivt_uncore_pci_ids) = { { /* end: all zeroes */ } }; -static struct pci_driver ivt_uncore_pci_driver = { - .name = "ivt_uncore", - .id_table = ivt_uncore_pci_ids, +static struct pci_driver ivbep_uncore_pci_driver = { + .name = "ivbep_uncore", + .id_table = ivbep_uncore_pci_ids, }; -int ivt_uncore_pci_init(void) +int ivbep_uncore_pci_init(void) { int ret = snbep_pci2phy_map_init(0x0e1e); if (ret) return ret; - uncore_pci_uncores = ivt_pci_uncores; - uncore_pci_driver = &ivt_uncore_pci_driver; + uncore_pci_uncores = ivbep_pci_uncores; + uncore_pci_driver = &ivbep_uncore_pci_driver; return 0; } /* end of IvyTown uncore support */ -- GitLab From 2e39465abc4b7856a0ea6fcf4f6b4668bb5db877 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 4 Aug 2014 12:07:15 +0200 Subject: [PATCH 0209/5088] locking: Remove deprecated smp_mb__() barriers Its been a while and there are no in-tree users left, so remove the deprecated barriers. Signed-off-by: Peter Zijlstra Cc: Chen, Gong Cc: Jacob Pan Cc: Joe Perches Cc: John Sullivan Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Srinivas Pandruvada Cc: Theodore Ts'o Signed-off-by: Ingo Molnar --- include/linux/atomic.h | 36 ------------------------------------ include/linux/bitops.h | 20 -------------------- kernel/sched/core.c | 16 ---------------- 3 files changed, 72 deletions(-) diff --git a/include/linux/atomic.h b/include/linux/atomic.h index fef3a809e7cf..5b08a8540ecf 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -3,42 +3,6 @@ #define _LINUX_ATOMIC_H #include -/* - * Provide __deprecated wrappers for the new interface, avoid flag day changes. - * We need the ugly external functions to break header recursion hell. - */ -#ifndef smp_mb__before_atomic_inc -static inline void __deprecated smp_mb__before_atomic_inc(void) -{ - extern void __smp_mb__before_atomic(void); - __smp_mb__before_atomic(); -} -#endif - -#ifndef smp_mb__after_atomic_inc -static inline void __deprecated smp_mb__after_atomic_inc(void) -{ - extern void __smp_mb__after_atomic(void); - __smp_mb__after_atomic(); -} -#endif - -#ifndef smp_mb__before_atomic_dec -static inline void __deprecated smp_mb__before_atomic_dec(void) -{ - extern void __smp_mb__before_atomic(void); - __smp_mb__before_atomic(); -} -#endif - -#ifndef smp_mb__after_atomic_dec -static inline void __deprecated smp_mb__after_atomic_dec(void) -{ - extern void __smp_mb__after_atomic(void); - __smp_mb__after_atomic(); -} -#endif - /** * atomic_add_unless - add unless the number is already a given value * @v: pointer of type atomic_t diff --git a/include/linux/bitops.h b/include/linux/bitops.h index cbc5833fb221..be5fd38bd5a0 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -32,26 +32,6 @@ extern unsigned long __sw_hweight64(__u64 w); */ #include -/* - * Provide __deprecated wrappers for the new interface, avoid flag day changes. - * We need the ugly external functions to break header recursion hell. - */ -#ifndef smp_mb__before_clear_bit -static inline void __deprecated smp_mb__before_clear_bit(void) -{ - extern void __smp_mb__before_atomic(void); - __smp_mb__before_atomic(); -} -#endif - -#ifndef smp_mb__after_clear_bit -static inline void __deprecated smp_mb__after_clear_bit(void) -{ - extern void __smp_mb__after_atomic(void); - __smp_mb__after_atomic(); -} -#endif - #define for_each_set_bit(bit, addr, size) \ for ((bit) = find_first_bit((addr), (size)); \ (bit) < (size); \ diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 1211575a2208..76c518c9b3a7 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -90,22 +90,6 @@ #define CREATE_TRACE_POINTS #include -#ifdef smp_mb__before_atomic -void __smp_mb__before_atomic(void) -{ - smp_mb__before_atomic(); -} -EXPORT_SYMBOL(__smp_mb__before_atomic); -#endif - -#ifdef smp_mb__after_atomic -void __smp_mb__after_atomic(void) -{ - smp_mb__after_atomic(); -} -EXPORT_SYMBOL(__smp_mb__after_atomic); -#endif - void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period) { unsigned long delta; -- GitLab From 242489cfe97d44290e7f88b12591fab6c0819045 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 30 Jul 2014 13:41:50 -0700 Subject: [PATCH 0210/5088] locking/mutexes: Standardize arguments in lock/unlock slowpaths Just how the locking-end behaves, when unlocking, go ahead and obtain the proper data structure immediately after the previous (asm-end) call exits and there are (probably) pending waiters. This simplifies a bit some of the layering. Signed-off-by: Davidlohr Bueso Signed-off-by: Peter Zijlstra Cc: jason.low2@hp.com Cc: aswin@hp.com Cc: mingo@kernel.org Cc: Linus Torvalds Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/1406752916-3341-1-git-send-email-davidlohr@hp.com Signed-off-by: Ingo Molnar --- kernel/locking/mutex.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index ae712b25e492..ad0e3335c481 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -679,9 +679,8 @@ EXPORT_SYMBOL_GPL(__ww_mutex_lock_interruptible); * Release the lock, slowpath: */ static inline void -__mutex_unlock_common_slowpath(atomic_t *lock_count, int nested) +__mutex_unlock_common_slowpath(struct mutex *lock, int nested) { - struct mutex *lock = container_of(lock_count, struct mutex, count); unsigned long flags; /* @@ -716,7 +715,9 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested) __visible void __mutex_unlock_slowpath(atomic_t *lock_count) { - __mutex_unlock_common_slowpath(lock_count, 1); + struct mutex *lock = container_of(lock_count, struct mutex, count); + + __mutex_unlock_common_slowpath(lock, 1); } #ifndef CONFIG_DEBUG_LOCK_ALLOC -- GitLab From 42fa566bd74aa7b95413fb00611ec983b488222d Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 30 Jul 2014 13:41:51 -0700 Subject: [PATCH 0211/5088] locking/mutexes: Document quick lock release when unlocking When unlocking, we always want to reach the slowpath with the lock's counter indicating it is unlocked. -- as returned by the asm fastpath call or by explicitly setting it. While doing so, at least in theory, we can optimize and allow faster lock stealing. When unlocking, we always want to reach the slowpath with the lock's counter indicating it is unlocked. -- as returned by the asm fastpath call or by explicitly setting it. While doing so, at least in theory, we can optimize and allow faster lock stealing. Signed-off-by: Davidlohr Bueso Signed-off-by: Peter Zijlstra Cc: jason.low2@hp.com Cc: aswin@hp.com Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1406752916-3341-2-git-send-email-davidlohr@hp.com Signed-off-by: Ingo Molnar --- kernel/locking/mutex.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index ad0e3335c481..93bec48f09ed 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -684,9 +684,16 @@ __mutex_unlock_common_slowpath(struct mutex *lock, int nested) unsigned long flags; /* - * some architectures leave the lock unlocked in the fastpath failure + * As a performance measurement, release the lock before doing other + * wakeup related duties to follow. This allows other tasks to acquire + * the lock sooner, while still handling cleanups in past unlock calls. + * This can be done as we do not enforce strict equivalence between the + * mutex counter and wait_list. + * + * + * Some architectures leave the lock unlocked in the fastpath failure * case, others need to leave it locked. In the later case we have to - * unlock it here + * unlock it here - as the lock counter is currently 0 or negative. */ if (__mutex_slowpath_needs_to_unlock()) atomic_set(&lock->count, 1); -- GitLab From aa9fc0c19bee0cbc152e0e06488095fb69229236 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 30 Jul 2014 13:41:52 -0700 Subject: [PATCH 0212/5088] locking/mcs: Remove obsolete comment ... as we clearly inline mcs_spin_lock() now. Signed-off-by: Davidlohr Bueso Acked-by: Jason Low Signed-off-by: Peter Zijlstra Cc: aswin@hp.com Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1406752916-3341-3-git-send-email-davidlohr@hp.com Signed-off-by: Ingo Molnar --- kernel/locking/mcs_spinlock.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/kernel/locking/mcs_spinlock.h b/kernel/locking/mcs_spinlock.h index 23e89c5930e9..4d60986fcbee 100644 --- a/kernel/locking/mcs_spinlock.h +++ b/kernel/locking/mcs_spinlock.h @@ -56,9 +56,6 @@ do { \ * If the lock has already been acquired, then this will proceed to spin * on this node->locked until the previous lock holder sets the node->locked * in mcs_spin_unlock(). - * - * We don't inline mcs_spin_lock() so that perf can correctly account for the - * time spent in this lock function. */ static inline void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node) -- GitLab From 76916515d9d84e6552ee5e218e0ed566ad75e600 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 30 Jul 2014 13:41:53 -0700 Subject: [PATCH 0213/5088] locking/mutexes: Refactor optimistic spinning code When we fail to acquire the mutex in the fastpath, we end up calling __mutex_lock_common(). A *lot* goes on in this function. Move out the optimistic spinning code into mutex_optimistic_spin() and simplify the former a bit. Furthermore, this is similar to what we have in rwsems. No logical changes. Signed-off-by: Davidlohr Bueso Acked-by: Jason Low Signed-off-by: Peter Zijlstra Cc: aswin@hp.com Cc: mingo@kernel.org Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1406752916-3341-4-git-send-email-davidlohr@hp.com Signed-off-by: Ingo Molnar --- kernel/locking/mutex.c | 396 ++++++++++++++++++++++------------------- 1 file changed, 214 insertions(+), 182 deletions(-) diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index 93bec48f09ed..0d8b6ed93874 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -106,6 +106,92 @@ void __sched mutex_lock(struct mutex *lock) EXPORT_SYMBOL(mutex_lock); #endif +static __always_inline void ww_mutex_lock_acquired(struct ww_mutex *ww, + struct ww_acquire_ctx *ww_ctx) +{ +#ifdef CONFIG_DEBUG_MUTEXES + /* + * If this WARN_ON triggers, you used ww_mutex_lock to acquire, + * but released with a normal mutex_unlock in this call. + * + * This should never happen, always use ww_mutex_unlock. + */ + DEBUG_LOCKS_WARN_ON(ww->ctx); + + /* + * Not quite done after calling ww_acquire_done() ? + */ + DEBUG_LOCKS_WARN_ON(ww_ctx->done_acquire); + + if (ww_ctx->contending_lock) { + /* + * After -EDEADLK you tried to + * acquire a different ww_mutex? Bad! + */ + DEBUG_LOCKS_WARN_ON(ww_ctx->contending_lock != ww); + + /* + * You called ww_mutex_lock after receiving -EDEADLK, + * but 'forgot' to unlock everything else first? + */ + DEBUG_LOCKS_WARN_ON(ww_ctx->acquired > 0); + ww_ctx->contending_lock = NULL; + } + + /* + * Naughty, using a different class will lead to undefined behavior! + */ + DEBUG_LOCKS_WARN_ON(ww_ctx->ww_class != ww->ww_class); +#endif + ww_ctx->acquired++; +} + +/* + * after acquiring lock with fastpath or when we lost out in contested + * slowpath, set ctx and wake up any waiters so they can recheck. + * + * This function is never called when CONFIG_DEBUG_LOCK_ALLOC is set, + * as the fastpath and opportunistic spinning are disabled in that case. + */ +static __always_inline void +ww_mutex_set_context_fastpath(struct ww_mutex *lock, + struct ww_acquire_ctx *ctx) +{ + unsigned long flags; + struct mutex_waiter *cur; + + ww_mutex_lock_acquired(lock, ctx); + + lock->ctx = ctx; + + /* + * The lock->ctx update should be visible on all cores before + * the atomic read is done, otherwise contended waiters might be + * missed. The contended waiters will either see ww_ctx == NULL + * and keep spinning, or it will acquire wait_lock, add itself + * to waiter list and sleep. + */ + smp_mb(); /* ^^^ */ + + /* + * Check if lock is contended, if not there is nobody to wake up + */ + if (likely(atomic_read(&lock->base.count) == 0)) + return; + + /* + * Uh oh, we raced in fastpath, wake up everyone in this case, + * so they can see the new lock->ctx. + */ + spin_lock_mutex(&lock->base.wait_lock, flags); + list_for_each_entry(cur, &lock->base.wait_list, list) { + debug_mutex_wake_waiter(&lock->base, cur); + wake_up_process(cur->task); + } + spin_unlock_mutex(&lock->base.wait_lock, flags); +} + + #ifdef CONFIG_MUTEX_SPIN_ON_OWNER /* * In order to avoid a stampede of mutex spinners from acquiring the mutex @@ -180,6 +266,129 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock) */ return retval; } + +/* + * Atomically try to take the lock when it is available + */ +static inline bool mutex_try_to_acquire(struct mutex *lock) +{ + return !mutex_is_locked(lock) && + (atomic_cmpxchg(&lock->count, 1, 0) == 1); +} + +/* + * Optimistic spinning. + * + * We try to spin for acquisition when we find that the lock owner + * is currently running on a (different) CPU and while we don't + * need to reschedule. The rationale is that if the lock owner is + * running, it is likely to release the lock soon. + * + * Since this needs the lock owner, and this mutex implementation + * doesn't track the owner atomically in the lock field, we need to + * track it non-atomically. + * + * We can't do this for DEBUG_MUTEXES because that relies on wait_lock + * to serialize everything. + * + * The mutex spinners are queued up using MCS lock so that only one + * spinner can compete for the mutex. However, if mutex spinning isn't + * going to happen, there is no point in going through the lock/unlock + * overhead. + * + * Returns true when the lock was taken, otherwise false, indicating + * that we need to jump to the slowpath and sleep. + */ +static bool mutex_optimistic_spin(struct mutex *lock, + struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx) +{ + struct task_struct *task = current; + + if (!mutex_can_spin_on_owner(lock)) + goto done; + + if (!osq_lock(&lock->osq)) + goto done; + + while (true) { + struct task_struct *owner; + + if (use_ww_ctx && ww_ctx->acquired > 0) { + struct ww_mutex *ww; + + ww = container_of(lock, struct ww_mutex, base); + /* + * If ww->ctx is set the contents are undefined, only + * by acquiring wait_lock there is a guarantee that + * they are not invalid when reading. + * + * As such, when deadlock detection needs to be + * performed the optimistic spinning cannot be done. + */ + if (ACCESS_ONCE(ww->ctx)) + break; + } + + /* + * If there's an owner, wait for it to either + * release the lock or go to sleep. + */ + owner = ACCESS_ONCE(lock->owner); + if (owner && !mutex_spin_on_owner(lock, owner)) + break; + + /* Try to acquire the mutex if it is unlocked. */ + if (mutex_try_to_acquire(lock)) { + lock_acquired(&lock->dep_map, ip); + + if (use_ww_ctx) { + struct ww_mutex *ww; + ww = container_of(lock, struct ww_mutex, base); + + ww_mutex_set_context_fastpath(ww, ww_ctx); + } + + mutex_set_owner(lock); + osq_unlock(&lock->osq); + return true; + } + + /* + * When there's no owner, we might have preempted between the + * owner acquiring the lock and setting the owner field. If + * we're an RT task that will live-lock because we won't let + * the owner complete. + */ + if (!owner && (need_resched() || rt_task(task))) + break; + + /* + * The cpu_relax() call is a compiler barrier which forces + * everything in this loop to be re-loaded. We don't need + * memory barriers as we'll eventually observe the right + * values at the cost of a few extra spins. + */ + cpu_relax_lowlatency(); + } + + osq_unlock(&lock->osq); +done: + /* + * If we fell out of the spin path because of need_resched(), + * reschedule now, before we try-lock the mutex. This avoids getting + * scheduled out right after we obtained the mutex. + */ + if (need_resched()) + schedule_preempt_disabled(); + + return false; +} +#else +static bool mutex_optimistic_spin(struct mutex *lock, + struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx) +{ + return false; +} #endif __visible __used noinline @@ -277,91 +486,6 @@ __mutex_lock_check_stamp(struct mutex *lock, struct ww_acquire_ctx *ctx) return 0; } -static __always_inline void ww_mutex_lock_acquired(struct ww_mutex *ww, - struct ww_acquire_ctx *ww_ctx) -{ -#ifdef CONFIG_DEBUG_MUTEXES - /* - * If this WARN_ON triggers, you used ww_mutex_lock to acquire, - * but released with a normal mutex_unlock in this call. - * - * This should never happen, always use ww_mutex_unlock. - */ - DEBUG_LOCKS_WARN_ON(ww->ctx); - - /* - * Not quite done after calling ww_acquire_done() ? - */ - DEBUG_LOCKS_WARN_ON(ww_ctx->done_acquire); - - if (ww_ctx->contending_lock) { - /* - * After -EDEADLK you tried to - * acquire a different ww_mutex? Bad! - */ - DEBUG_LOCKS_WARN_ON(ww_ctx->contending_lock != ww); - - /* - * You called ww_mutex_lock after receiving -EDEADLK, - * but 'forgot' to unlock everything else first? - */ - DEBUG_LOCKS_WARN_ON(ww_ctx->acquired > 0); - ww_ctx->contending_lock = NULL; - } - - /* - * Naughty, using a different class will lead to undefined behavior! - */ - DEBUG_LOCKS_WARN_ON(ww_ctx->ww_class != ww->ww_class); -#endif - ww_ctx->acquired++; -} - -/* - * after acquiring lock with fastpath or when we lost out in contested - * slowpath, set ctx and wake up any waiters so they can recheck. - * - * This function is never called when CONFIG_DEBUG_LOCK_ALLOC is set, - * as the fastpath and opportunistic spinning are disabled in that case. - */ -static __always_inline void -ww_mutex_set_context_fastpath(struct ww_mutex *lock, - struct ww_acquire_ctx *ctx) -{ - unsigned long flags; - struct mutex_waiter *cur; - - ww_mutex_lock_acquired(lock, ctx); - - lock->ctx = ctx; - - /* - * The lock->ctx update should be visible on all cores before - * the atomic read is done, otherwise contended waiters might be - * missed. The contended waiters will either see ww_ctx == NULL - * and keep spinning, or it will acquire wait_lock, add itself - * to waiter list and sleep. - */ - smp_mb(); /* ^^^ */ - - /* - * Check if lock is contended, if not there is nobody to wake up - */ - if (likely(atomic_read(&lock->base.count) == 0)) - return; - - /* - * Uh oh, we raced in fastpath, wake up everyone in this case, - * so they can see the new lock->ctx. - */ - spin_lock_mutex(&lock->base.wait_lock, flags); - list_for_each_entry(cur, &lock->base.wait_list, list) { - debug_mutex_wake_waiter(&lock->base, cur); - wake_up_process(cur->task); - } - spin_unlock_mutex(&lock->base.wait_lock, flags); -} - /* * Lock a mutex (possibly interruptible), slowpath: */ @@ -378,104 +502,12 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, preempt_disable(); mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip); -#ifdef CONFIG_MUTEX_SPIN_ON_OWNER - /* - * Optimistic spinning. - * - * We try to spin for acquisition when we find that the lock owner - * is currently running on a (different) CPU and while we don't - * need to reschedule. The rationale is that if the lock owner is - * running, it is likely to release the lock soon. - * - * Since this needs the lock owner, and this mutex implementation - * doesn't track the owner atomically in the lock field, we need to - * track it non-atomically. - * - * We can't do this for DEBUG_MUTEXES because that relies on wait_lock - * to serialize everything. - * - * The mutex spinners are queued up using MCS lock so that only one - * spinner can compete for the mutex. However, if mutex spinning isn't - * going to happen, there is no point in going through the lock/unlock - * overhead. - */ - if (!mutex_can_spin_on_owner(lock)) - goto slowpath; - - if (!osq_lock(&lock->osq)) - goto slowpath; - - for (;;) { - struct task_struct *owner; - - if (use_ww_ctx && ww_ctx->acquired > 0) { - struct ww_mutex *ww; - - ww = container_of(lock, struct ww_mutex, base); - /* - * If ww->ctx is set the contents are undefined, only - * by acquiring wait_lock there is a guarantee that - * they are not invalid when reading. - * - * As such, when deadlock detection needs to be - * performed the optimistic spinning cannot be done. - */ - if (ACCESS_ONCE(ww->ctx)) - break; - } - - /* - * If there's an owner, wait for it to either - * release the lock or go to sleep. - */ - owner = ACCESS_ONCE(lock->owner); - if (owner && !mutex_spin_on_owner(lock, owner)) - break; - - /* Try to acquire the mutex if it is unlocked. */ - if (!mutex_is_locked(lock) && - (atomic_cmpxchg(&lock->count, 1, 0) == 1)) { - lock_acquired(&lock->dep_map, ip); - if (use_ww_ctx) { - struct ww_mutex *ww; - ww = container_of(lock, struct ww_mutex, base); - - ww_mutex_set_context_fastpath(ww, ww_ctx); - } - - mutex_set_owner(lock); - osq_unlock(&lock->osq); - preempt_enable(); - return 0; - } - - /* - * When there's no owner, we might have preempted between the - * owner acquiring the lock and setting the owner field. If - * we're an RT task that will live-lock because we won't let - * the owner complete. - */ - if (!owner && (need_resched() || rt_task(task))) - break; - - /* - * The cpu_relax() call is a compiler barrier which forces - * everything in this loop to be re-loaded. We don't need - * memory barriers as we'll eventually observe the right - * values at the cost of a few extra spins. - */ - cpu_relax_lowlatency(); + if (mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx)) { + /* got the lock, yay! */ + preempt_enable(); + return 0; } - osq_unlock(&lock->osq); -slowpath: - /* - * If we fell out of the spin path because of need_resched(), - * reschedule now, before we try-lock the mutex. This avoids getting - * scheduled out right after we obtained the mutex. - */ - if (need_resched()) - schedule_preempt_disabled(); -#endif + spin_lock_mutex(&lock->wait_lock, flags); /* -- GitLab From 7608a43d8f2e02f8b532f8e11481d7ecf8b5d3f9 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 30 Jul 2014 13:41:54 -0700 Subject: [PATCH 0214/5088] locking/mutexes: Use MUTEX_SPIN_ON_OWNER when appropriate 4badad35 ("locking/mutex: Disable optimistic spinning on some architectures") added a ARCH_SUPPORTS_ATOMIC_RMW flag to disable the mutex optimistic feature on specific archs. Because CONFIG_MUTEX_SPIN_ON_OWNER only depended on DEBUG and SMP, it was ok to have the ->owner field conditional a bit flexible. However by adding a new variable to the matter, we can waste space with the unused field, ie: CONFIG_SMP && (!CONFIG_MUTEX_SPIN_ON_OWNER && !CONFIG_DEBUG_MUTEX). Signed-off-by: Davidlohr Bueso Acked-by: Jason Low Signed-off-by: Peter Zijlstra Cc: aswin@hp.com Cc: Davidlohr Bueso Cc: Heiko Carstens Cc: Jason Low Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Tim Chen Link: http://lkml.kernel.org/r/1406752916-3341-5-git-send-email-davidlohr@hp.com Signed-off-by: Ingo Molnar --- include/linux/mutex.h | 2 +- kernel/locking/mutex.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/mutex.h b/include/linux/mutex.h index 8d5535c58cc2..e4c29418f407 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -52,7 +52,7 @@ struct mutex { atomic_t count; spinlock_t wait_lock; struct list_head wait_list; -#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) +#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER) struct task_struct *owner; #endif #ifdef CONFIG_MUTEX_SPIN_ON_OWNER diff --git a/kernel/locking/mutex.h b/kernel/locking/mutex.h index 4115fbf83b12..5cda397607f2 100644 --- a/kernel/locking/mutex.h +++ b/kernel/locking/mutex.h @@ -16,7 +16,7 @@ #define mutex_remove_waiter(lock, waiter, ti) \ __list_del((waiter)->list.prev, (waiter)->list.next) -#ifdef CONFIG_SMP +#ifdef CONFIG_MUTEX_SPIN_ON_OWNER static inline void mutex_set_owner(struct mutex *lock) { lock->owner = current; -- GitLab From 214e0aed639ef40987bf6159fad303171a6de31e Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 30 Jul 2014 13:41:55 -0700 Subject: [PATCH 0215/5088] locking/Documentation: Move locking related docs into Documentation/locking/ Specifically: Documentation/locking/lockdep-design.txt Documentation/locking/lockstat.txt Documentation/locking/mutex-design.txt Documentation/locking/rt-mutex-design.txt Documentation/locking/rt-mutex.txt Documentation/locking/spinlocks.txt Documentation/locking/ww-mutex-design.txt Signed-off-by: Davidlohr Bueso Acked-by: Randy Dunlap Signed-off-by: Peter Zijlstra Cc: jason.low2@hp.com Cc: aswin@hp.com Cc: Alexei Starovoitov Cc: Al Viro Cc: Andrew Morton Cc: Chris Mason Cc: Dan Streetman Cc: David Airlie Cc: Davidlohr Bueso Cc: David S. Miller Cc: Greg Kroah-Hartman Cc: Heiko Carstens Cc: Jason Low Cc: Josef Bacik Cc: Kees Cook Cc: Linus Torvalds Cc: Lubomir Rintel Cc: Masanari Iida Cc: Paul E. McKenney Cc: Randy Dunlap Cc: Tim Chen Cc: Vineet Gupta Cc: fengguang.wu@intel.com Link: http://lkml.kernel.org/r/1406752916-3341-6-git-send-email-davidlohr@hp.com Signed-off-by: Ingo Molnar --- Documentation/00-INDEX | 2 ++ Documentation/DocBook/kernel-locking.tmpl | 2 +- Documentation/{ => locking}/lockdep-design.txt | 0 Documentation/{ => locking}/lockstat.txt | 2 +- Documentation/{ => locking}/mutex-design.txt | 0 Documentation/{ => locking}/rt-mutex-design.txt | 0 Documentation/{ => locking}/rt-mutex.txt | 0 Documentation/{ => locking}/spinlocks.txt | 14 +++++++------- Documentation/{ => locking}/ww-mutex-design.txt | 0 MAINTAINERS | 4 ++-- drivers/gpu/drm/drm_modeset_lock.c | 2 +- include/linux/lockdep.h | 2 +- include/linux/mutex.h | 2 +- include/linux/rwsem.h | 2 +- kernel/locking/mutex.c | 2 +- kernel/locking/rtmutex.c | 2 +- lib/Kconfig.debug | 4 ++-- 17 files changed, 21 insertions(+), 19 deletions(-) rename Documentation/{ => locking}/lockdep-design.txt (100%) rename Documentation/{ => locking}/lockstat.txt (99%) rename Documentation/{ => locking}/mutex-design.txt (100%) rename Documentation/{ => locking}/rt-mutex-design.txt (100%) rename Documentation/{ => locking}/rt-mutex.txt (100%) rename Documentation/{ => locking}/spinlocks.txt (98%) rename Documentation/{ => locking}/ww-mutex-design.txt (100%) diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 27e67a98b7be..1750fcef1ab4 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -287,6 +287,8 @@ local_ops.txt - semantics and behavior of local atomic operations. lockdep-design.txt - documentation on the runtime locking correctness validator. +locking/ + - directory with info about kernel locking primitives lockstat.txt - info on collecting statistics on locks (and contention). lockup-watchdogs.txt diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl index e584ee12a1e7..7c9cc4846cb6 100644 --- a/Documentation/DocBook/kernel-locking.tmpl +++ b/Documentation/DocBook/kernel-locking.tmpl @@ -1972,7 +1972,7 @@ machines due to caching. - Documentation/spinlocks.txt: + Documentation/locking/spinlocks.txt: Linus Torvalds' spinlocking tutorial in the kernel sources. diff --git a/Documentation/lockdep-design.txt b/Documentation/locking/lockdep-design.txt similarity index 100% rename from Documentation/lockdep-design.txt rename to Documentation/locking/lockdep-design.txt diff --git a/Documentation/lockstat.txt b/Documentation/locking/lockstat.txt similarity index 99% rename from Documentation/lockstat.txt rename to Documentation/locking/lockstat.txt index 72d010689751..7428773a1e69 100644 --- a/Documentation/lockstat.txt +++ b/Documentation/locking/lockstat.txt @@ -12,7 +12,7 @@ Because things like lock contention can severely impact performance. - HOW Lockdep already has hooks in the lock functions and maps lock instances to -lock classes. We build on that (see Documentation/lockdep-design.txt). +lock classes. We build on that (see Documentation/lokcing/lockdep-design.txt). The graph below shows the relation between the lock functions and the various hooks therein. diff --git a/Documentation/mutex-design.txt b/Documentation/locking/mutex-design.txt similarity index 100% rename from Documentation/mutex-design.txt rename to Documentation/locking/mutex-design.txt diff --git a/Documentation/rt-mutex-design.txt b/Documentation/locking/rt-mutex-design.txt similarity index 100% rename from Documentation/rt-mutex-design.txt rename to Documentation/locking/rt-mutex-design.txt diff --git a/Documentation/rt-mutex.txt b/Documentation/locking/rt-mutex.txt similarity index 100% rename from Documentation/rt-mutex.txt rename to Documentation/locking/rt-mutex.txt diff --git a/Documentation/spinlocks.txt b/Documentation/locking/spinlocks.txt similarity index 98% rename from Documentation/spinlocks.txt rename to Documentation/locking/spinlocks.txt index 97eaf5727178..ff35e40bdf5b 100644 --- a/Documentation/spinlocks.txt +++ b/Documentation/locking/spinlocks.txt @@ -105,9 +105,9 @@ never used in interrupt handlers, you can use the non-irq versions: spin_unlock(&lock); (and the equivalent read-write versions too, of course). The spinlock will -guarantee the same kind of exclusive access, and it will be much faster. +guarantee the same kind of exclusive access, and it will be much faster. This is useful if you know that the data in question is only ever -manipulated from a "process context", ie no interrupts involved. +manipulated from a "process context", ie no interrupts involved. The reasons you mustn't use these versions if you have interrupts that play with the spinlock is that you can get deadlocks: @@ -122,21 +122,21 @@ the other interrupt happens on another CPU, but it is _not_ ok if the interrupt happens on the same CPU that already holds the lock, because the lock will obviously never be released (because the interrupt is waiting for the lock, and the lock-holder is interrupted by the interrupt and will -not continue until the interrupt has been processed). +not continue until the interrupt has been processed). (This is also the reason why the irq-versions of the spinlocks only need to disable the _local_ interrupts - it's ok to use spinlocks in interrupts on other CPU's, because an interrupt on another CPU doesn't interrupt the CPU that holds the lock, so the lock-holder can continue and eventually -releases the lock). +releases the lock). Note that you can be clever with read-write locks and interrupts. For example, if you know that the interrupt only ever gets a read-lock, then you can use a non-irq version of read locks everywhere - because they -don't block on each other (and thus there is no dead-lock wrt interrupts. -But when you do the write-lock, you have to use the irq-safe version. +don't block on each other (and thus there is no dead-lock wrt interrupts. +But when you do the write-lock, you have to use the irq-safe version. -For an example of being clever with rw-locks, see the "waitqueue_lock" +For an example of being clever with rw-locks, see the "waitqueue_lock" handling in kernel/sched/core.c - nothing ever _changes_ a wait-queue from within an interrupt, they only read the queue in order to know whom to wake up. So read-locks are safe (which is good: they are very common diff --git a/Documentation/ww-mutex-design.txt b/Documentation/locking/ww-mutex-design.txt similarity index 100% rename from Documentation/ww-mutex-design.txt rename to Documentation/locking/ww-mutex-design.txt diff --git a/MAINTAINERS b/MAINTAINERS index 1acc624ecfd7..aac481fcbf5c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5523,8 +5523,8 @@ M: Ingo Molnar L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/locking S: Maintained -F: Documentation/lockdep*.txt -F: Documentation/lockstat.txt +F: Documentation/locking/lockdep*.txt +F: Documentation/locking/lockstat.txt F: include/linux/lockdep.h F: kernel/locking/ diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 0dc57d5ecd10..3a02e5e3e9f3 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -35,7 +35,7 @@ * of extra utility/tracking out of our acquire-ctx. This is provided * by drm_modeset_lock / drm_modeset_acquire_ctx. * - * For basic principles of ww_mutex, see: Documentation/ww-mutex-design.txt + * For basic principles of ww_mutex, see: Documentation/locking/ww-mutex-design.txt * * The basic usage pattern is to: * diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 008388f920d7..f388481201cd 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -4,7 +4,7 @@ * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra * - * see Documentation/lockdep-design.txt for more details. + * see Documentation/locking/lockdep-design.txt for more details. */ #ifndef __LINUX_LOCKDEP_H #define __LINUX_LOCKDEP_H diff --git a/include/linux/mutex.h b/include/linux/mutex.h index e4c29418f407..cc31498fc526 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -133,7 +133,7 @@ static inline int mutex_is_locked(struct mutex *lock) /* * See kernel/locking/mutex.c for detailed documentation of these APIs. - * Also see Documentation/mutex-design.txt. + * Also see Documentation/locking/mutex-design.txt. */ #ifdef CONFIG_DEBUG_LOCK_ALLOC extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass); diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h index 035d3c57fc8a..8f498cdde280 100644 --- a/include/linux/rwsem.h +++ b/include/linux/rwsem.h @@ -149,7 +149,7 @@ extern void downgrade_write(struct rw_semaphore *sem); * static then another method for expressing nested locking is * the explicit definition of lock class keys and the use of * lockdep_set_class() at lock initialization time. - * See Documentation/lockdep-design.txt for more details.) + * See Documentation/locking/lockdep-design.txt for more details.) */ extern void down_read_nested(struct rw_semaphore *sem, int subclass); extern void down_write_nested(struct rw_semaphore *sem, int subclass); diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index 0d8b6ed93874..dadbf88c22c4 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -15,7 +15,7 @@ * by Steven Rostedt, based on work by Gregory Haskins, Peter Morreale * and Sven Dietrich. * - * Also see Documentation/mutex-design.txt. + * Also see Documentation/locking/mutex-design.txt. */ #include #include diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index a0ea2a141b3b..7c98873a3077 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -8,7 +8,7 @@ * Copyright (C) 2005 Kihon Technologies Inc., Steven Rostedt * Copyright (C) 2006 Esben Nielsen * - * See Documentation/rt-mutex-design.txt for details. + * See Documentation/locking/rt-mutex-design.txt for details. */ #include #include diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 901096d31c66..9b94a063e26c 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -924,7 +924,7 @@ config PROVE_LOCKING the proof of observed correctness is also maintained for an arbitrary combination of these separate locking variants. - For more details, see Documentation/lockdep-design.txt. + For more details, see Documentation/locking/lockdep-design.txt. config LOCKDEP bool @@ -945,7 +945,7 @@ config LOCK_STAT help This feature enables tracking lock contention points - For more details, see Documentation/lockstat.txt + For more details, see Documentation/locking/lockstat.txt This also enables lock events required by "perf lock", subcommand of perf. -- GitLab From 0a7cbf9abe3198461de3d3e97268db32a646ba06 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 30 Jul 2014 13:41:56 -0700 Subject: [PATCH 0216/5088] locking/Documentation: Update locking/mutex-design.txt disadvantages Fortunately Jason was able to reduce some of the overhead we had introduced in the original rwsem optimistic spinning - an it is now the same size as mutexes. Update the documentation accordingly. Signed-off-by: Davidlohr Bueso Acked-by: Jason Low Signed-off-by: Peter Zijlstra Cc: aswin@hp.com Cc: Linus Torvalds Cc: Randy Dunlap Link: http://lkml.kernel.org/r/1406752916-3341-7-git-send-email-davidlohr@hp.com Signed-off-by: Ingo Molnar --- Documentation/locking/mutex-design.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/locking/mutex-design.txt b/Documentation/locking/mutex-design.txt index ee231ed09ec6..60c482df1a38 100644 --- a/Documentation/locking/mutex-design.txt +++ b/Documentation/locking/mutex-design.txt @@ -145,9 +145,9 @@ Disadvantages Unlike its original design and purpose, 'struct mutex' is larger than most locks in the kernel. E.g: on x86-64 it is 40 bytes, almost twice -as large as 'struct semaphore' (24 bytes) and 8 bytes shy of the -'struct rw_semaphore' variant. Larger structure sizes mean more CPU -cache and memory footprint. +as large as 'struct semaphore' (24 bytes) and tied, along with rwsems, +for the largest lock in the kernel. Larger structure sizes mean more +CPU cache and memory footprint. When to use mutexes ------------------- -- GitLab From 4999201a59ef555f9105d2bb2459ed895627f7aa Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 8 Aug 2014 12:35:36 +0200 Subject: [PATCH 0217/5088] locking/spinlocks: Always evaluate the second argument of spin_lock_nested() Evaluating a macro argument only if certain configuration options have been selected is confusing and error-prone. Hence always evaluate the second argument of spin_lock_nested(). An intentional side effect of this patch is that it avoids that the following warning is reported for netif_addr_lock_nested() when building with CONFIG_DEBUG_LOCK_ALLOC=n and with W=1: include/linux/netdevice.h: In function 'netif_addr_lock_nested': include/linux/netdevice.h:2865:6: warning: variable 'subclass' set but not used [-Wunused-but-set-variable] int subclass = SINGLE_DEPTH_NESTING; ^ Signed-off-by: Bart Van Assche Signed-off-by: Peter Zijlstra Cc: David Rientjes Cc: David S. Miller Cc: Andrew Morton Cc: Linus Torvalds Cc: Oleg Nesterov Cc: Paul E. McKenney Link: http://lkml.kernel.org/r/53E4A7F8.1040700@acm.org Signed-off-by: Ingo Molnar --- include/linux/spinlock.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 3f2867ff0ced..262ba4ef9a8e 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -197,7 +197,13 @@ static inline void do_raw_spin_unlock(raw_spinlock_t *lock) __releases(lock) _raw_spin_lock_nest_lock(lock, &(nest_lock)->dep_map); \ } while (0) #else -# define raw_spin_lock_nested(lock, subclass) _raw_spin_lock(lock) +/* + * Always evaluate the 'subclass' argument to avoid that the compiler + * warns about set-but-not-used variables when building with + * CONFIG_DEBUG_LOCK_ALLOC=n and with W=1. + */ +# define raw_spin_lock_nested(lock, subclass) \ + _raw_spin_lock(((void)(subclass), (lock))) # define raw_spin_lock_nest_lock(lock, nest_lock) _raw_spin_lock(lock) #endif -- GitLab From f0bab73cb539fb803c4d419951e8d28aa4964f8f Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Wed, 6 Aug 2014 13:22:01 -0400 Subject: [PATCH 0218/5088] locking/lockdep: Restrict the use of recursive read_lock() with qrwlock Unlike the original unfair rwlock implementation, queued rwlock will grant lock according to the chronological sequence of the lock requests except when the lock requester is in the interrupt context. Consequently, recursive read_lock calls will now hang the process if there is a write_lock call somewhere in between the read_lock calls. This patch updates the lockdep implementation to look for recursive read_lock calls. A new read state (3) is used to mark those read_lock call that cannot be recursively called except in the interrupt context. The new read state does exhaust the 2 bits available in held_lock:read bit field. The addition of any new read state in the future may require a redesign of how all those bits are squeezed together in the held_lock structure. Signed-off-by: Waiman Long Signed-off-by: Peter Zijlstra Cc: Maarten Lankhorst Cc: Rik van Riel Cc: Scott J Norton Cc: Fengguang Wu Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1407345722-61615-2-git-send-email-Waiman.Long@hp.com Signed-off-by: Ingo Molnar --- include/linux/lockdep.h | 10 +++++++++- kernel/locking/lockdep.c | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index f388481201cd..b5a84b62fb84 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -478,16 +478,24 @@ static inline void print_irqtrace_events(struct task_struct *curr) * on the per lock-class debug mode: */ +/* + * Read states in the 2-bit held_lock:read field: + * 0: Exclusive lock + * 1: Shareable lock, cannot be recursively called + * 2: Shareable lock, can be recursively called + * 3: Shareable lock, cannot be recursively called except in interrupt context + */ #define lock_acquire_exclusive(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, n, i) #define lock_acquire_shared(l, s, t, n, i) lock_acquire(l, s, t, 1, 1, n, i) #define lock_acquire_shared_recursive(l, s, t, n, i) lock_acquire(l, s, t, 2, 1, n, i) +#define lock_acquire_shared_irecursive(l, s, t, n, i) lock_acquire(l, s, t, 3, 1, n, i) #define spin_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) #define spin_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) #define spin_release(l, n, i) lock_release(l, n, i) #define rwlock_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) -#define rwlock_acquire_read(l, s, t, i) lock_acquire_shared_recursive(l, s, t, NULL, i) +#define rwlock_acquire_read(l, s, t, i) lock_acquire_shared_irecursive(l, s, t, NULL, i) #define rwlock_release(l, n, i) lock_release(l, n, i) #define seqcount_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 88d0d4420ad2..420ba685c4e5 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3597,6 +3597,12 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass, raw_local_irq_save(flags); check_flags(flags); + /* + * An interrupt recursive read in interrupt context can be considered + * to be the same as a recursive read from checking perspective. + */ + if ((read == 3) && in_interrupt()) + read = 2; current->lockdep_recursion = 1; trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip); __lock_acquire(lock, subclass, trylock, read, check, -- GitLab From ae17ea0ec7d8fa64fbb773a52b2df5ba4766bcb8 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Wed, 6 Aug 2014 13:22:02 -0400 Subject: [PATCH 0219/5088] locking/selftest: Support queued rwlock The queued rwlock does not support the use of recursive read-lock in the process context. With changes in the lockdep code to check and disallow recursive read-lock, it is also necessary for the locking selftest to be updated to change the process context recursive read locking results from SUCCESS to FAILURE for rwlock. Signed-off-by: Waiman Long Signed-off-by: Peter Zijlstra Cc: Maarten Lankhorst Cc: Rik van Riel Cc: Scott J Norton Cc: Fengguang Wu Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1407345722-61615-3-git-send-email-Waiman.Long@hp.com Signed-off-by: Ingo Molnar --- lib/locking-selftest.c | 56 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c index 872a15a2a637..62af709b2083 100644 --- a/lib/locking-selftest.c +++ b/lib/locking-selftest.c @@ -267,19 +267,46 @@ GENERATE_TESTCASE(AA_rsem) #undef E /* - * Special-case for read-locking, they are - * allowed to recurse on the same lock class: + * Special-case for read-locking, they are not allowed to + * recurse on the same lock class except under interrupt context: */ static void rlock_AA1(void) { RL(X1); - RL(X1); // this one should NOT fail + RL(X1); // this one should fail } static void rlock_AA1B(void) { RL(X1); - RL(X2); // this one should NOT fail + RL(X2); // this one should fail +} + +static void rlock_AHA1(void) +{ + RL(X1); + HARDIRQ_ENTER(); + RL(X1); // this one should NOT fail + HARDIRQ_EXIT(); +} + +static void rlock_AHA1B(void) +{ + RL(X1); + HARDIRQ_ENTER(); + RL(X2); // this one should NOT fail + HARDIRQ_EXIT(); +} + +static void rlock_ASAHA1(void) +{ + RL(X1); + SOFTIRQ_ENTER(); + RL(X1); // this one should NOT fail + HARDIRQ_ENTER(); + RL(X1); // this one should NOT fail + HARDIRQ_EXIT(); + SOFTIRQ_EXIT(); } static void rsem_AA1(void) @@ -1069,7 +1096,7 @@ static inline void print_testname(const char *testname) print_testname(desc); \ dotest(name##_spin, FAILURE, LOCKTYPE_SPIN); \ dotest(name##_wlock, FAILURE, LOCKTYPE_RWLOCK); \ - dotest(name##_rlock, SUCCESS, LOCKTYPE_RWLOCK); \ + dotest(name##_rlock, FAILURE, LOCKTYPE_RWLOCK); \ dotest(name##_mutex, FAILURE, LOCKTYPE_MUTEX); \ dotest(name##_wsem, FAILURE, LOCKTYPE_RWSEM); \ dotest(name##_rsem, FAILURE, LOCKTYPE_RWSEM); \ @@ -1830,14 +1857,14 @@ void locking_selftest(void) printk(" --------------------------------------------------------------------------\n"); print_testname("recursive read-lock"); printk(" |"); - dotest(rlock_AA1, SUCCESS, LOCKTYPE_RWLOCK); + dotest(rlock_AA1, FAILURE, LOCKTYPE_RWLOCK); printk(" |"); dotest(rsem_AA1, FAILURE, LOCKTYPE_RWSEM); printk("\n"); print_testname("recursive read-lock #2"); printk(" |"); - dotest(rlock_AA1B, SUCCESS, LOCKTYPE_RWLOCK); + dotest(rlock_AA1B, FAILURE, LOCKTYPE_RWLOCK); printk(" |"); dotest(rsem_AA1B, FAILURE, LOCKTYPE_RWSEM); printk("\n"); @@ -1856,6 +1883,21 @@ void locking_selftest(void) dotest(rsem_AA3, FAILURE, LOCKTYPE_RWSEM); printk("\n"); + print_testname("recursive rlock with interrupt"); + printk(" |"); + dotest(rlock_AHA1, SUCCESS, LOCKTYPE_RWLOCK); + printk("\n"); + + print_testname("recursive rlock with interrupt #2"); + printk(" |"); + dotest(rlock_AHA1B, SUCCESS, LOCKTYPE_RWLOCK); + printk("\n"); + + print_testname("recursive rlock with interrupt #3"); + printk(" |"); + dotest(rlock_ASAHA1, SUCCESS, LOCKTYPE_RWLOCK); + printk("\n"); + printk(" --------------------------------------------------------------------------\n"); /* -- GitLab From 4d884705dababd7d0f3f12796bc7b45e84962596 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:47 +0200 Subject: [PATCH 0220/5088] drm/i915: Track file_priv, not ctx in the ppgtt structure Hardware contexts reference a ppgtt, not the other way round. And the only user of this (in debugfs) actually only cares about which file the ppgtt is associated with. So give it what it wants. While at it give the ppgtt create function a proper name&place. Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 22 +--------------------- drivers/gpu/drm/i915/i915_gem_gtt.c | 21 +++++++++++++++++++++ drivers/gpu/drm/i915/i915_gem_gtt.h | 6 +++++- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 3b7decbeeed3..1c3a9943a742 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -333,7 +333,7 @@ static int per_file_stats(int id, void *ptr, void *data) } ppgtt = container_of(vma->vm, struct i915_hw_ppgtt, base); - if (ppgtt->ctx && ppgtt->ctx->file_priv != stats->file_priv) + if (ppgtt->file_priv != stats->file_priv) continue; if (obj->ring) /* XXX per-vma statistic */ diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index dc43d0263a01..90665872734d 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -184,26 +184,6 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size) return obj; } -static struct i915_hw_ppgtt * -create_vm_for_ctx(struct drm_device *dev, struct intel_context *ctx) -{ - struct i915_hw_ppgtt *ppgtt; - int ret; - - ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); - if (!ppgtt) - return ERR_PTR(-ENOMEM); - - ret = i915_ppgtt_init(dev, ppgtt); - if (ret) { - kfree(ppgtt); - return ERR_PTR(ret); - } - - ppgtt->ctx = ctx; - return ppgtt; -} - static struct intel_context * __create_hw_context(struct drm_device *dev, struct drm_i915_file_private *file_priv) @@ -290,7 +270,7 @@ i915_gem_create_context(struct drm_device *dev, } if (create_vm) { - struct i915_hw_ppgtt *ppgtt = create_vm_for_ctx(dev, ctx); + struct i915_hw_ppgtt *ppgtt = i915_ppgtt_create(dev, file_priv); if (IS_ERR_OR_NULL(ppgtt)) { DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n", diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 6ffa12b72538..a5715faba65f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1211,6 +1211,27 @@ int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) return ret; } +struct i915_hw_ppgtt * +i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv) +{ + struct i915_hw_ppgtt *ppgtt; + int ret; + + ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); + if (!ppgtt) + return ERR_PTR(-ENOMEM); + + ret = i915_ppgtt_init(dev, ppgtt); + if (ret) { + kfree(ppgtt); + return ERR_PTR(ret); + } + + ppgtt->file_priv = fpriv; + + return ppgtt; +} + void i915_ppgtt_release(struct kref *kref) { 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 c6beb528f955..90ff45246b62 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -34,6 +34,8 @@ #ifndef __I915_GEM_GTT_H__ #define __I915_GEM_GTT_H__ +struct drm_i915_file_private; + typedef uint32_t gen6_gtt_pte_t; typedef uint64_t gen8_gtt_pte_t; typedef gen8_gtt_pte_t gen8_ppgtt_pde_t; @@ -258,7 +260,7 @@ struct i915_hw_ppgtt { dma_addr_t *gen8_pt_dma_addr[4]; }; - struct intel_context *ctx; + struct drm_i915_file_private *file_priv; int (*enable)(struct i915_hw_ppgtt *ppgtt); int (*switch_mm)(struct i915_hw_ppgtt *ppgtt, @@ -275,6 +277,8 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); void i915_ppgtt_release(struct kref *kref); +struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_device *dev, + struct drm_i915_file_private *fpriv); static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt) { if (ppgtt) -- GitLab From 841cd7737557785c0f215b0984c06aaaaa882302 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:48 +0200 Subject: [PATCH 0221/5088] drm/i915: Only refcount ppgtt if it actually is one This essentially unbreaks non-ppgtt operation where we'd scribble over random memory. While at it give the vm_to_ppgtt function a proper prefix and make it a bit more paranoid. Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 10 +++++++++- drivers/gpu/drm/i915/i915_gem.c | 3 ++- drivers/gpu/drm/i915/i915_gem_gtt.c | 3 ++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 101fc637eb46..454badf31dfd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2512,6 +2512,15 @@ static inline bool i915_is_ggtt(struct i915_address_space *vm) return vm == ggtt; } +static inline struct i915_hw_ppgtt * +i915_vm_to_ppgtt(struct i915_address_space *vm) +{ + WARN_ON(i915_is_ggtt(vm)); + + return container_of(vm, struct i915_hw_ppgtt, base); +} + + static inline bool i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *obj) { return i915_gem_obj_bound(obj, obj_to_ggtt(obj)); @@ -2547,7 +2556,6 @@ void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj); /* i915_gem_context.c */ #define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base) -#define vm_to_ppgtt(vm) container_of(vm, struct i915_hw_ppgtt, base) 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); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8061d45eaa80..e3e30cd474be 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4485,7 +4485,8 @@ void i915_gem_vma_destroy(struct i915_vma *vma) vm = vma->vm; - i915_ppgtt_put(vm_to_ppgtt(vm)); + if (!i915_is_ggtt(vm)) + i915_ppgtt_put(i915_vm_to_ppgtt(vm)); list_del(&vma->vma_link); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a5715faba65f..48d8f4a21c3f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2187,7 +2187,8 @@ i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, if (!vma) vma = __i915_gem_vma_create(obj, vm); - i915_ppgtt_get(vm_to_ppgtt(vm)); + if (!i915_is_ggtt(vm)) + i915_ppgtt_get(i915_vm_to_ppgtt(vm)); return vma; } -- GitLab From 5dc383b05a05d05e964172d882603cd171040c5f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:49 +0200 Subject: [PATCH 0222/5088] drm/i915: Add proper prefix to obj_to_ggtt Stuff in headers really aught to have this. Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 11 ++++++----- drivers/gpu/drm/i915/i915_gem.c | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 454badf31dfd..2db22732c7ae 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2503,7 +2503,7 @@ static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) { } /* Some GGTT VM helpers */ -#define obj_to_ggtt(obj) \ +#define i915_obj_to_ggtt(obj) \ (&((struct drm_i915_private *)(obj)->base.dev->dev_private)->gtt.base) static inline bool i915_is_ggtt(struct i915_address_space *vm) { @@ -2523,19 +2523,19 @@ i915_vm_to_ppgtt(struct i915_address_space *vm) static inline bool i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *obj) { - return i915_gem_obj_bound(obj, obj_to_ggtt(obj)); + return i915_gem_obj_bound(obj, i915_obj_to_ggtt(obj)); } static inline unsigned long i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *obj) { - return i915_gem_obj_offset(obj, obj_to_ggtt(obj)); + return i915_gem_obj_offset(obj, i915_obj_to_ggtt(obj)); } static inline unsigned long i915_gem_obj_ggtt_size(struct drm_i915_gem_object *obj) { - return i915_gem_obj_size(obj, obj_to_ggtt(obj)); + return i915_gem_obj_size(obj, i915_obj_to_ggtt(obj)); } static inline int __must_check @@ -2543,7 +2543,8 @@ i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj, uint32_t alignment, unsigned flags) { - return i915_gem_object_pin(obj, obj_to_ggtt(obj), alignment, flags | PIN_GLOBAL); + return i915_gem_object_pin(obj, i915_obj_to_ggtt(obj), + alignment, flags | PIN_GLOBAL); } static inline int diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e3e30cd474be..c9d1396781e2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5252,7 +5252,7 @@ struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj) struct i915_vma *vma; vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link); - if (vma->vm != obj_to_ggtt(obj)) + if (vma->vm != i915_obj_to_ggtt(obj)) return NULL; return vma; -- GitLab From 6c5566a82c6fb1da9e13a294f23d4cd85a08cb30 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:50 +0200 Subject: [PATCH 0223/5088] drm/i915: Allow i915_gem_setup_global_gtt to fail We already needs this just as a safety check in case the preallocation reservation dance fails. But we definitely need this to be able to move tha aliasing ppgtt setup back out of the context code to this place, where it belongs. Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 7 ++++++- drivers/gpu/drm/i915/i915_gem_gtt.c | 16 ++++++++++------ drivers/gpu/drm/i915/i915_gem_gtt.h | 4 ++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c9d1396781e2..c8404a439502 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4754,7 +4754,12 @@ int i915_gem_init(struct drm_device *dev) dev_priv->gt.stop_ring = intel_logical_ring_stop; } - i915_gem_init_userptr(dev); + ret = i915_gem_init_userptr(dev); + if (ret) { + mutex_unlock(&dev->struct_mutex); + return ret; + } + i915_gem_init_global_gtt(dev); ret = i915_gem_context_init(dev); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 48d8f4a21c3f..d228f839ca4f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1698,10 +1698,10 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node, } } -void i915_gem_setup_global_gtt(struct drm_device *dev, - unsigned long start, - unsigned long mappable_end, - unsigned long end) +int i915_gem_setup_global_gtt(struct drm_device *dev, + unsigned long start, + unsigned long mappable_end, + unsigned long end) { /* Let GEM Manage all of the aperture. * @@ -1734,8 +1734,10 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, WARN_ON(i915_gem_obj_ggtt_bound(obj)); ret = drm_mm_reserve_node(&ggtt_vm->mm, &vma->node); - if (ret) - DRM_DEBUG_KMS("Reservation failed\n"); + if (ret) { + DRM_DEBUG_KMS("Reservation failed: %i\n", ret); + return ret; + } obj->has_global_gtt_mapping = 1; } @@ -1752,6 +1754,8 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, /* And finally clear the reserved guard page */ ggtt_vm->clear_range(ggtt_vm, end - PAGE_SIZE, PAGE_SIZE, true); + + return 0; } void i915_gem_init_global_gtt(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 90ff45246b62..0eb0dddff76b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -271,8 +271,8 @@ struct i915_hw_ppgtt { int i915_gem_gtt_init(struct drm_device *dev); void i915_gem_init_global_gtt(struct drm_device *dev); -void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, - unsigned long mappable_end, unsigned long end); +int i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, + unsigned long mappable_end, unsigned long end); int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); -- GitLab From 896ab1a5d54269b463a24194c2e4a369103b46d8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:51 +0200 Subject: [PATCH 0224/5088] drm/i915: Fix up checks for aliasing ppgtt A subsequent patch will no longer initialize the aliasing ppgtt if we have full ppgtt enabled, since we simply don't need that any more. Unfortunately a few places check for the aliasing ppgtt instead of checking for ppgtt in general. Fix them up. One special case are the gtt offset and size macros, which have some code to remap the aliasing ppgtt to the global gtt. The aliasing ppgtt is _not_ a logical address space, so passing that in as the vm is plain and simple a bug. So just WARN about it and carry on - we have a gracefully fall-through anyway if we can't find the vma. Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 4 +--- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_gem.c | 8 ++------ drivers/gpu/drm/i915/intel_ringbuffer.c | 4 +--- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index dea99d92fb4a..c45856bcc8b9 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -842,8 +842,6 @@ static u32 *vmap_batch(struct drm_i915_gem_object *obj) */ bool i915_needs_cmd_parser(struct intel_engine_cs *ring) { - struct drm_i915_private *dev_priv = ring->dev->dev_private; - if (!ring->needs_cmd_parser) return false; @@ -852,7 +850,7 @@ bool i915_needs_cmd_parser(struct intel_engine_cs *ring) * disabled. That will cause all of the parser's PPGTT checks to * fail. For now, disable parsing when PPGTT is off. */ - if (!dev_priv->mm.aliasing_ppgtt) + if (USES_PPGTT(ring->dev)) return false; return (i915.enable_cmd_parser == 1); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 1763fbf34e1d..895f9f2f35ea 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -999,7 +999,7 @@ static int i915_getparam(struct drm_device *dev, void *data, value = HAS_WT(dev); break; case I915_PARAM_HAS_ALIASING_PPGTT: - value = dev_priv->mm.aliasing_ppgtt || USES_FULL_PPGTT(dev); + value = USES_PPGTT(dev); break; case I915_PARAM_HAS_WAIT_TIMEOUT: value = 1; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c8404a439502..6a7795097017 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5106,9 +5106,7 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o, struct drm_i915_private *dev_priv = o->base.dev->dev_private; struct i915_vma *vma; - if (!dev_priv->mm.aliasing_ppgtt || - vm == &dev_priv->mm.aliasing_ppgtt->base) - vm = &dev_priv->gtt.base; + WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base); list_for_each_entry(vma, &o->vma_list, vma_link) { if (vma->vm == vm) @@ -5149,9 +5147,7 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o, struct drm_i915_private *dev_priv = o->base.dev->dev_private; struct i915_vma *vma; - if (!dev_priv->mm.aliasing_ppgtt || - vm == &dev_priv->mm.aliasing_ppgtt->base) - vm = &dev_priv->gtt.base; + WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base); BUG_ON(list_empty(&o->vma_list)); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 4236014c1cda..13543f8528c2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2006,9 +2006,7 @@ gen8_ring_dispatch_execbuffer(struct intel_engine_cs *ring, u64 offset, u32 len, unsigned flags) { - struct drm_i915_private *dev_priv = ring->dev->dev_private; - bool ppgtt = dev_priv->mm.aliasing_ppgtt != NULL && - !(flags & I915_DISPATCH_SECURE); + bool ppgtt = USES_PPGTT(ring->dev) && !(flags & I915_DISPATCH_SECURE); int ret; ret = intel_ring_begin(ring, 4); -- GitLab From 82460d97246a993aa49e88bf9b4154cce60f8da8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 20:19:53 +0200 Subject: [PATCH 0225/5088] drm/i915: Rework ppgtt init to no require an aliasing ppgtt Currently we abuse the aliasing ppgtt to set up the ppgtt support in general. Which is a bit backwards since with full ppgtt we don't ever need the aliasing ppgtt. So untangle this and separate the ppgtt init from the aliasing ppgtt. While at it drag it out of the context enabling (which just does a switch to the default context). Note that we still have the differentiation between synchronous and asynchronous ppgtt setup, but that will soon vanish. So also correctly wire up the return value handling to be prepared for when ->switch_mm drops the synchronous parameter and could start to fail. Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 8 +++ drivers/gpu/drm/i915/i915_gem_context.c | 7 --- drivers/gpu/drm/i915/i915_gem_gtt.c | 84 ++++++++++--------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 1 + 4 files changed, 42 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6a7795097017..6c2f0b886eb0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4719,6 +4719,14 @@ i915_gem_init_hw(struct drm_device *dev) if (ret && ret != -EIO) { DRM_ERROR("Context enable failed %d\n", ret); i915_gem_cleanup_ringbuffer(dev); + + return ret; + } + + ret = i915_ppgtt_init_hw(dev); + if (ret && ret != -EIO) { + DRM_ERROR("PPGTT enable failed %d\n", ret); + i915_gem_cleanup_ringbuffer(dev); } return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 90665872734d..eece059a8447 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -436,13 +436,6 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv) struct intel_engine_cs *ring; int ret, i; - /* This is the only place the aliasing PPGTT gets enabled, which means - * it has to happen before we bail on reset */ - if (dev_priv->mm.aliasing_ppgtt) { - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - ppgtt->enable(ppgtt); - } - /* FIXME: We should make this work, even in reset */ if (i915_reset_in_progress(&dev_priv->gpu_error)) return 0; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index d228f839ca4f..b7dcf72126f9 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -67,7 +67,6 @@ static void ppgtt_bind_vma(struct i915_vma *vma, enum i915_cache_level cache_level, u32 flags); static void ppgtt_unbind_vma(struct i915_vma *vma); -static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt); static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr, enum i915_cache_level level, @@ -604,7 +603,6 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size) kunmap_atomic(pd_vaddr); } - ppgtt->enable = gen8_ppgtt_enable; ppgtt->switch_mm = gen8_mm_switch; ppgtt->base.clear_range = gen8_ppgtt_clear_range; ppgtt->base.insert_entries = gen8_ppgtt_insert_entries; @@ -825,39 +823,20 @@ static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt, return 0; } -static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) +static void gen8_ppgtt_enable(struct drm_device *dev) { - struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring; - int j, ret; + int j; for_each_ring(ring, dev_priv, j) { I915_WRITE(RING_MODE_GEN7(ring), _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); - - /* We promise to do a switch later with FULL PPGTT. If this is - * aliasing, this is the one and only switch we'll do */ - if (USES_FULL_PPGTT(dev)) - continue; - - ret = ppgtt->switch_mm(ppgtt, ring, true); - if (ret) - goto err_out; } - - return 0; - -err_out: - for_each_ring(ring, dev_priv, j) - I915_WRITE(RING_MODE_GEN7(ring), - _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE)); - return ret; } -static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) +static void gen7_ppgtt_enable(struct drm_device *dev) { - struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring; uint32_t ecochk, ecobits; @@ -876,31 +855,16 @@ static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) I915_WRITE(GAM_ECOCHK, ecochk); for_each_ring(ring, dev_priv, i) { - int ret; /* GFX_MODE is per-ring on gen7+ */ I915_WRITE(RING_MODE_GEN7(ring), _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); - - /* We promise to do a switch later with FULL PPGTT. If this is - * aliasing, this is the one and only switch we'll do */ - if (USES_FULL_PPGTT(dev)) - continue; - - ret = ppgtt->switch_mm(ppgtt, ring, true); - if (ret) - return ret; } - - return 0; } -static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) +static void gen6_ppgtt_enable(struct drm_device *dev) { - struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_engine_cs *ring; uint32_t ecochk, gab_ctl, ecobits; - int i; ecobits = I915_READ(GAC_ECO_BITS); I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT | @@ -913,14 +877,6 @@ static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B); I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); - - for_each_ring(ring, dev_priv, i) { - int ret = ppgtt->switch_mm(ppgtt, ring, true); - if (ret) - return ret; - } - - return 0; } /* PPGTT support for Sandybdrige/Gen6 and later */ @@ -1140,13 +1096,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode; if (IS_GEN6(dev)) { - ppgtt->enable = gen6_ppgtt_enable; ppgtt->switch_mm = gen6_mm_switch; } else if (IS_HASWELL(dev)) { - ppgtt->enable = gen7_ppgtt_enable; ppgtt->switch_mm = hsw_mm_switch; } else if (IS_GEN7(dev)) { - ppgtt->enable = gen7_ppgtt_enable; ppgtt->switch_mm = gen7_mm_switch; } else BUG(); @@ -1211,6 +1164,35 @@ int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) return ret; } +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; + + if (!USES_PPGTT(dev)) + return 0; + + if (IS_GEN6(dev)) + gen6_ppgtt_enable(dev); + else if (IS_GEN7(dev)) + gen7_ppgtt_enable(dev); + else if (INTEL_INFO(dev)->gen >= 8) + gen8_ppgtt_enable(dev); + else + WARN_ON(1); + + if (ppgtt) { + for_each_ring(ring, dev_priv, i) { + ret = ppgtt->switch_mm(ppgtt, ring, true); + if (ret != 0) + return ret; + } + } + + return ret; +} 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 0eb0dddff76b..98fbb7309ea5 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -276,6 +276,7 @@ int i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); +int i915_ppgtt_init_hw(struct drm_device *dev); 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 fa76da3499f1789f0e37d3bbcdc320bdf47c89ca Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 20:19:54 +0200 Subject: [PATCH 0226/5088] drm/i915: Initialize the aliasing ppgtt as part of global gtt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stuffing this into the context setup code doesn't make a lot of sense. Also reusing the real ppgtt setup code makes even less sense since the aliasing ppgtt isn't a real address space. Leaving all that stuff unitialized will make sure that we catch any abusers promptly. This is also a prep work to clean up the context->ppgtt link. v2: Fix up the logic fail, I've fumbled it so badly to completely disable ppgtt on gen6. Spotted by Ville and Michel. Also move around the pde write into the gen6 init function, since otherwise it won't work at all. v3: Only initialize the aliasing ppgtt when we actually enable it. Cc: "Thierry, Michel" Cc: Ville Syrjälä Reviewed-by: Michel Thierry [danvet: Squash in fixup from Fengguang Wu.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 13 +------- drivers/gpu/drm/i915/i915_gem_gtt.c | 42 ++++++++++++++++++------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index eece059a8447..7093f5df9ee7 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -279,17 +279,6 @@ i915_gem_create_context(struct drm_device *dev, goto err_unpin; } else ctx->vm = &ppgtt->base; - - /* This case is reserved for the global default context and - * should only happen once. */ - if (is_global_default_ctx) { - if (WARN_ON(dev_priv->mm.aliasing_ppgtt)) { - ret = -EEXIST; - goto err_unpin; - } - - dev_priv->mm.aliasing_ppgtt = ppgtt; - } } else if (USES_PPGTT(dev)) { /* For platforms which only have aliasing PPGTT, we fake the * address space and refcounting. */ @@ -368,7 +357,7 @@ int i915_gem_context_init(struct drm_device *dev) } } - ctx = i915_gem_create_context(dev, NULL, USES_PPGTT(dev)); + ctx = i915_gem_create_context(dev, NULL, USES_FULL_PPGTT(dev)); if (IS_ERR(ctx)) { DRM_ERROR("Failed to create default global context (error %ld)\n", PTR_ERR(ctx)); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b7dcf72126f9..b033ff770ac4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1130,35 +1130,38 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->node.size >> 20, ppgtt->node.start / PAGE_SIZE); + gen6_write_pdes(ppgtt); + DRM_DEBUG("Adding PPGTT at offset %x\n", + ppgtt->pd_offset << 10); + return 0; } -int i915_ppgtt_init(struct drm_device *dev, 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; - int ret = 0; ppgtt->base.dev = dev; ppgtt->base.scratch = dev_priv->gtt.base.scratch; if (INTEL_INFO(dev)->gen < 8) - ret = gen6_ppgtt_init(ppgtt); + return gen6_ppgtt_init(ppgtt); else if (IS_GEN8(dev)) - ret = gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total); + return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total); else BUG(); +} +int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret = 0; - if (!ret) { - struct drm_i915_private *dev_priv = dev->dev_private; + ret = __hw_ppgtt_init(dev, ppgtt); + if (ret == 0) { kref_init(&ppgtt->ref); drm_mm_init(&ppgtt->base.mm, ppgtt->base.start, ppgtt->base.total); i915_init_vm(dev_priv, &ppgtt->base); - if (INTEL_INFO(dev)->gen < 8) { - gen6_write_pdes(ppgtt); - DRM_DEBUG("Adding PPGTT at offset %x\n", - ppgtt->pd_offset << 10); - } } return ret; @@ -1699,6 +1702,7 @@ int i915_gem_setup_global_gtt(struct drm_device *dev, struct drm_mm_node *entry; struct drm_i915_gem_object *obj; unsigned long hole_start, hole_end; + int ret; BUG_ON(mappable_end > end); @@ -1710,7 +1714,7 @@ int i915_gem_setup_global_gtt(struct drm_device *dev, /* Mark any preallocated objects as occupied */ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { struct i915_vma *vma = i915_gem_obj_to_vma(obj, ggtt_vm); - int ret; + DRM_DEBUG_KMS("reserving preallocated space: %lx + %zx\n", i915_gem_obj_ggtt_offset(obj), obj->base.size); @@ -1737,6 +1741,20 @@ int i915_gem_setup_global_gtt(struct drm_device *dev, /* And finally clear the reserved guard page */ ggtt_vm->clear_range(ggtt_vm, end - PAGE_SIZE, PAGE_SIZE, true); + if (USES_PPGTT(dev) && !USES_FULL_PPGTT(dev)) { + struct i915_hw_ppgtt *ppgtt; + + ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); + if (!ppgtt) + return -ENOMEM; + + ret = __hw_ppgtt_init(dev, ppgtt); + if (ret != 0) + return ret; + + dev_priv->mm.aliasing_ppgtt = ppgtt; + } + return 0; } -- GitLab From ae6c4806927b8b0781ecc187aa16b10c820fc430 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:53 +0200 Subject: [PATCH 0227/5088] drm/i915: Only track real ppgtt for a context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a bit a confusion since we track the global gtt, the aliasing and real ppgtt in the ctx->vm pointer. And not all callers really bother to check for the different cases and just presume that it points to a real ppgtt. Now looking closely we don't actually need ->vm to always point at an address space - the only place that cares actually has fixup code already to decide whether to look at the per-proces or the global address space. So switch to just tracking the ppgtt directly and ditch all the extraneous code. v2: Fixup the ppgtt debugfs file to not oops on a NULL ctx->ppgtt. Also drop the early exit - without aliasing ppgtt we want to dump all the ppgtts of the contexts if we have full ppgtt. v3: Actually git add the compile fix. Reviewed-by: Michel Thierry Cc: "Thierry, Michel" Cc: Ville Syrjälä OTC-Jira: VIZ-3724 [danvet: Resolve conflicts with execlist patches while applying.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 11 ++++++-- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/i915_gem_context.c | 33 +++++++--------------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 5 ++-- drivers/gpu/drm/i915/i915_gpu_error.c | 10 +++++-- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 6 files changed, 30 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 1c3a9943a742..d42db6bc34e0 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1821,7 +1821,13 @@ static int per_file_ctx(int id, void *ptr, void *data) { struct intel_context *ctx = ptr; struct seq_file *m = data; - struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(ctx); + struct i915_hw_ppgtt *ppgtt = ctx->ppgtt; + + if (!ppgtt) { + seq_printf(m, " no ppgtt for context %d\n", + ctx->user_handle); + return 0; + } if (i915_gem_context_is_default(ctx)) seq_puts(m, " default context:\n"); @@ -1881,8 +1887,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev) seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset); ppgtt->debug_dump(ppgtt, m); - } else - return; + } list_for_each_entry_reverse(file, &dev->filelist, lhead) { struct drm_i915_file_private *file_priv = file->driver_priv; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2db22732c7ae..eb99a109c0bc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -624,7 +624,7 @@ struct intel_context { uint8_t remap_slice; struct drm_i915_file_private *file_priv; struct i915_ctx_hang_stats hang_stats; - struct i915_address_space *vm; + struct i915_hw_ppgtt *ppgtt; /* Legacy ring buffer submission */ struct { @@ -2556,7 +2556,6 @@ i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj) void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj); /* i915_gem_context.c */ -#define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base) 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); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 7093f5df9ee7..206bf2d6c554 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -135,19 +135,13 @@ static int get_context_size(struct drm_device *dev) void i915_gem_context_free(struct kref *ctx_ref) { struct intel_context *ctx = container_of(ctx_ref, - typeof(*ctx), ref); - struct i915_hw_ppgtt *ppgtt = NULL; + typeof(*ctx), ref); - if (i915.enable_execlists) { - ppgtt = ctx_to_ppgtt(ctx); + if (i915.enable_execlists) intel_lr_context_free(ctx); - } else if (ctx->legacy_hw_ctx.rcs_state) { - /* We refcount even the aliasing PPGTT to keep the code symmetric */ - if (USES_PPGTT(ctx->legacy_hw_ctx.rcs_state->base.dev)) - ppgtt = ctx_to_ppgtt(ctx); - } - i915_ppgtt_put(ppgtt); + i915_ppgtt_put(ctx->ppgtt); + if (ctx->legacy_hw_ctx.rcs_state) drm_gem_object_unreference(&ctx->legacy_hw_ctx.rcs_state->base); list_del(&ctx->link); @@ -243,7 +237,6 @@ i915_gem_create_context(struct drm_device *dev, bool create_vm) { const bool is_global_default_ctx = file_priv == NULL; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_context *ctx; int ret = 0; @@ -277,15 +270,10 @@ i915_gem_create_context(struct drm_device *dev, PTR_ERR(ppgtt)); ret = PTR_ERR(ppgtt); goto err_unpin; - } else - ctx->vm = &ppgtt->base; - } else if (USES_PPGTT(dev)) { - /* For platforms which only have aliasing PPGTT, we fake the - * address space and refcounting. */ - ctx->vm = &dev_priv->mm.aliasing_ppgtt->base; - i915_ppgtt_get(dev_priv->mm.aliasing_ppgtt); - } else - ctx->vm = &dev_priv->gtt.base; + } + + ctx->ppgtt = ppgtt; + } return ctx; @@ -543,7 +531,6 @@ static int do_switch(struct intel_engine_cs *ring, { struct drm_i915_private *dev_priv = ring->dev->dev_private; struct intel_context *from = ring->last_context; - struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(to); u32 hw_flags = 0; bool uninitialized = false; int ret, i; @@ -571,8 +558,8 @@ static int do_switch(struct intel_engine_cs *ring, */ from = ring->last_context; - if (USES_FULL_PPGTT(ring->dev)) { - ret = ppgtt->switch_mm(ppgtt, ring, false); + if (to->ppgtt) { + ret = to->ppgtt->switch_mm(to->ppgtt, ring, false); if (ret) goto unpin_out; } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 7e04a4825ed0..1a0611bb576b 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1315,8 +1315,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_context_reference(ctx); - vm = ctx->vm; - if (!USES_FULL_PPGTT(dev)) + if (ctx->ppgtt) + vm = &ctx->ppgtt->base; + else vm = &dev_priv->gtt.base; eb = eb_create(args); diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index eab41f9390f8..fc11ac6b0373 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -967,6 +967,12 @@ static void i915_gem_record_rings(struct drm_device *dev, request = i915_gem_find_active_request(ring); if (request) { + struct i915_address_space *vm; + + vm = request->ctx && request->ctx->ppgtt ? + &request->ctx->ppgtt->base : + &dev_priv->gtt.base; + /* We need to copy these to an anonymous buffer * as the simplest method to avoid being overwritten * by userspace. @@ -974,9 +980,7 @@ static void i915_gem_record_rings(struct drm_device *dev, error->ring[i].batchbuffer = i915_error_object_create(dev_priv, request->batch_obj, - request->ctx ? - request->ctx->vm : - &dev_priv->gtt.base); + vm); if (HAS_BROKEN_CS_TLB(dev_priv->dev) && ring->scratch.obj) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 6f1b64e01a05..6b5f416b5c0d 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -904,7 +904,7 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o struct intel_engine_cs *ring, struct intel_ringbuffer *ringbuf) { struct drm_i915_gem_object *ring_obj = ringbuf->obj; - struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(ctx); + struct i915_hw_ppgtt *ppgtt = ctx->ppgtt; struct page *page; uint32_t *reg_state; int ret; -- GitLab From d624d86e1e3b69cadb2dad42588e71e9a3b6d70a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:54 +0200 Subject: [PATCH 0228/5088] drm/i915: Drop create_vm argument to i915_gem_create_context Now that all the flow is streamlined the rule is simple: We create a new ppgtt for a new context when we have full ppgtt enabled. Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 206bf2d6c554..9683e62ec61a 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -233,8 +233,7 @@ __create_hw_context(struct drm_device *dev, */ static struct intel_context * i915_gem_create_context(struct drm_device *dev, - struct drm_i915_file_private *file_priv, - bool create_vm) + struct drm_i915_file_private *file_priv) { const bool is_global_default_ctx = file_priv == NULL; struct intel_context *ctx; @@ -262,7 +261,7 @@ i915_gem_create_context(struct drm_device *dev, } } - if (create_vm) { + if (USES_FULL_PPGTT(dev)) { struct i915_hw_ppgtt *ppgtt = i915_ppgtt_create(dev, file_priv); if (IS_ERR_OR_NULL(ppgtt)) { @@ -345,7 +344,7 @@ int i915_gem_context_init(struct drm_device *dev) } } - ctx = i915_gem_create_context(dev, NULL, USES_FULL_PPGTT(dev)); + ctx = i915_gem_create_context(dev, NULL); if (IS_ERR(ctx)) { DRM_ERROR("Failed to create default global context (error %ld)\n", PTR_ERR(ctx)); @@ -444,7 +443,7 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file) idr_init(&file_priv->context_idr); mutex_lock(&dev->struct_mutex); - ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev)); + ctx = i915_gem_create_context(dev, file_priv); mutex_unlock(&dev->struct_mutex); if (IS_ERR(ctx)) { @@ -702,7 +701,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, if (ret) return ret; - ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev)); + ctx = i915_gem_create_context(dev, file_priv); mutex_unlock(&dev->struct_mutex); if (IS_ERR(ctx)) return PTR_ERR(ctx); -- GitLab From 19dd120ceee085dbac70b1b01bd09d599cf87bd0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:55 +0200 Subject: [PATCH 0229/5088] drm/i915: Extract common cleanup into i915_ppgtt_release Address space cleanup isn't really a job for the low-level cleanup callbacks. Without this change we can't reuse the low-level cleanup callback for the aliasing ppgtt cleanup. Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b033ff770ac4..c1e2d9a9f9e2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -391,9 +391,6 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) struct i915_hw_ppgtt *ppgtt = container_of(vm, struct i915_hw_ppgtt, base); - list_del(&vm->global_link); - drm_mm_takedown(&vm->mm); - gen8_ppgtt_unmap_pages(ppgtt); gen8_ppgtt_free(ppgtt); } @@ -974,8 +971,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) struct i915_hw_ppgtt *ppgtt = container_of(vm, struct i915_hw_ppgtt, base); - list_del(&vm->global_link); - drm_mm_takedown(&ppgtt->base.mm); drm_mm_remove_node(&ppgtt->node); gen6_ppgtt_unmap_pages(ppgtt); @@ -1226,6 +1221,9 @@ void i915_ppgtt_release(struct kref *kref) WARN_ON(!list_empty(&ppgtt->base.active_list)); WARN_ON(!list_empty(&ppgtt->base.inactive_list)); + list_del(&ppgtt->base.global_link); + drm_mm_takedown(&ppgtt->base.mm); + ppgtt->base.cleanup(&ppgtt->base); kfree(ppgtt); } -- GitLab From 90d0a0e8d0e64c92c4a6147f3c7cdc7c544d6b1a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:56 +0200 Subject: [PATCH 0230/5088] drm/i915: Extract commmon global gtt cleanup code We want to move the aliasing ppgtt cleanup back into the global gtt cleanup code for symmetry, but first we need to create such a place. Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 20 ++++++++++++-------- drivers/gpu/drm/i915/i915_gem_gtt.h | 1 + 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 895f9f2f35ea..c9af48503f76 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1821,7 +1821,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) arch_phys_wc_del(dev_priv->gtt.mtrr); io_mapping_free(dev_priv->gtt.mappable); out_gtt: - dev_priv->gtt.base.cleanup(&dev_priv->gtt.base); + i915_global_gtt_cleanup(dev); out_regs: intel_uncore_fini(dev); pci_iounmap(dev->pdev, dev_priv->regs); @@ -1920,7 +1920,7 @@ int i915_driver_unload(struct drm_device *dev) destroy_workqueue(dev_priv->wq); pm_qos_remove_request(&dev_priv->pm_qos); - dev_priv->gtt.base.cleanup(&dev_priv->gtt.base); + i915_global_gtt_cleanup(dev); intel_uncore_fini(dev); if (dev_priv->regs != NULL) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index c1e2d9a9f9e2..8d94e3582045 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1767,6 +1767,18 @@ void i915_gem_init_global_gtt(struct drm_device *dev) i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); } +void i915_global_gtt_cleanup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_address_space *vm = &dev_priv->gtt.base; + + if (drm_mm_initialized(&vm->mm)) { + drm_mm_takedown(&vm->mm); + list_del(&vm->global_link); + } + + vm->cleanup(vm); +} static int setup_scratch_page(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2035,10 +2047,6 @@ static void gen6_gmch_remove(struct i915_address_space *vm) struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base); - if (drm_mm_initialized(&vm->mm)) { - drm_mm_takedown(&vm->mm); - list_del(&vm->global_link); - } iounmap(gtt->gsm); teardown_scratch_page(vm->dev); } @@ -2071,10 +2079,6 @@ static int i915_gmch_probe(struct drm_device *dev, static void i915_gmch_remove(struct i915_address_space *vm) { - if (drm_mm_initialized(&vm->mm)) { - drm_mm_takedown(&vm->mm); - list_del(&vm->global_link); - } intel_gmch_remove(); } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 98fbb7309ea5..6280648d4805 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -273,6 +273,7 @@ int i915_gem_gtt_init(struct drm_device *dev); void i915_gem_init_global_gtt(struct drm_device *dev); int i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, unsigned long mappable_end, unsigned long end); +void i915_global_gtt_cleanup(struct drm_device *dev); int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); -- GitLab From 70e32544aa4027b4c27226da32eb3866e7bbbcdc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 6 Aug 2014 15:04:57 +0200 Subject: [PATCH 0231/5088] drm/i915: Cleanup aliasging ppgtt alongside the global gtt Also remove related WARN_ONs which seem to have been hit since a rather long time. But apperently no one noticed since our module reload is already WARNING-infested :( Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 4 ---- drivers/gpu/drm/i915/i915_gem_gtt.c | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index c9af48503f76..04dd6112865e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1388,7 +1388,6 @@ static int i915_load_modeset_init(struct drm_device *dev) i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); - WARN_ON(dev_priv->mm.aliasing_ppgtt); cleanup_irq: drm_irq_uninstall(dev); cleanup_gem_stolen: @@ -1901,7 +1900,6 @@ int i915_driver_unload(struct drm_device *dev) mutex_lock(&dev->struct_mutex); i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); - WARN_ON(dev_priv->mm.aliasing_ppgtt); mutex_unlock(&dev->struct_mutex); i915_gem_cleanup_stolen(dev); @@ -1909,8 +1907,6 @@ int i915_driver_unload(struct drm_device *dev) i915_free_hws(dev); } - WARN_ON(!list_empty(&dev_priv->vm_list)); - drm_vblank_cleanup(dev); intel_teardown_gmbus(dev); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 8d94e3582045..d97b280861ee 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1772,6 +1772,12 @@ void i915_global_gtt_cleanup(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct i915_address_space *vm = &dev_priv->gtt.base; + if (dev_priv->mm.aliasing_ppgtt) { + struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + + ppgtt->base.cleanup(&ppgtt->base); + } + if (drm_mm_initialized(&vm->mm)) { drm_mm_takedown(&vm->mm); list_del(&vm->global_link); @@ -1779,6 +1785,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev) vm->cleanup(vm); } + static int setup_scratch_page(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; -- GitLab From a08a42ad441e113f87308e0844049cb881f1ac1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 12 Aug 2014 19:39:52 +0300 Subject: [PATCH 0232/5088] drm/i915: Don't try to enable cursor from setplane when crtc is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure the cursor gets fully clipped when enabling it on a disabled crtc via setplane. This will prevent the lower level code from attempting to enable the cursor in hardware. Cc: Paulo Zanoni Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- 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 1bd1aa21a8e9..a93d5ffd3863 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11743,8 +11743,8 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, }; const struct drm_rect clip = { /* integer pixels */ - .x2 = intel_crtc->config.pipe_src_w, - .y2 = intel_crtc->config.pipe_src_h, + .x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0, + .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0, }; bool visible; int ret; -- GitLab From d7ce484eeec43079ad842f1d351f53998ed6bb30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 12 Aug 2014 19:39:53 +0300 Subject: [PATCH 0233/5088] drm/i915: Move CURSIZE setup to i845_update_cursor() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CURSIZE register exists on 845/865 only, so move it to i845_update_cursor(). Changes to cursor size must be done only when the cursor is disabled, so do the write just before enabling the cursor. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a93d5ffd3863..cd3dc3b72798 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8070,6 +8070,7 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base) CURSOR_GAMMA_ENABLE | CURSOR_FORMAT_ARGB); if (intel_crtc->cursor_cntl != cntl) { + I915_WRITE(CURSIZE, (64 << 12) | 64); I915_WRITE(_CURACNTR, cntl); POSTING_READ(_CURACNTR); intel_crtc->cursor_cntl = cntl; @@ -8219,7 +8220,6 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc, uint32_t width, uint32_t height) { 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; unsigned old_width; @@ -8292,9 +8292,6 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc, addr = obj->phys_handle->busaddr; } - if (IS_GEN2(dev)) - I915_WRITE(CURSIZE, (height << 12) | width); - finish: if (intel_crtc->cursor_bo) { if (!INTEL_INFO(dev)->cursor_needs_physical) -- GitLab From 8ac5466926daef2406f7b25e9a272567cb81adb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 12 Aug 2014 19:39:54 +0300 Subject: [PATCH 0234/5088] drm/i915: Unify ivb_update_cursor() and i9xx_update_cursor() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ever since commit 5efb3e2838536832c9b6872512e6b6daf592cee9 Author: Ville Syrjälä Date: Wed Apr 9 13:28:53 2014 +0300 drm/i915/chv: Add cursor pipe offsets the only difference between i9xx_update_cursor() and ivb_update_cursor() was the hsw+ pipe csc handling. Let's unify them and we can rid outselves of some duplicated code. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 41 +--------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cd3dc3b72798..b3fb127131f0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8104,43 +8104,6 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base) } cntl |= pipe << 28; /* Connect to correct pipe */ } - if (intel_crtc->cursor_cntl != cntl) { - I915_WRITE(CURCNTR(pipe), cntl); - POSTING_READ(CURCNTR(pipe)); - intel_crtc->cursor_cntl = cntl; - } - - /* and commit changes on next vblank */ - I915_WRITE(CURBASE(pipe), base); - POSTING_READ(CURBASE(pipe)); -} - -static void ivb_update_cursor(struct drm_crtc *crtc, u32 base) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; - uint32_t cntl; - - cntl = 0; - if (base) { - cntl = MCURSOR_GAMMA_ENABLE; - switch (intel_crtc->cursor_width) { - case 64: - cntl |= CURSOR_MODE_64_ARGB_AX; - break; - case 128: - cntl |= CURSOR_MODE_128_ARGB_AX; - break; - case 256: - cntl |= CURSOR_MODE_256_ARGB_AX; - break; - default: - WARN_ON(1); - return; - } - } if (IS_HASWELL(dev) || IS_BROADWELL(dev)) cntl |= CURSOR_PIPE_CSC_ENABLE; @@ -8199,9 +8162,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, I915_WRITE(CURPOS(pipe), pos); - if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev)) - ivb_update_cursor(crtc, base); - else if (IS_845G(dev) || IS_I865G(dev)) + if (IS_845G(dev) || IS_I865G(dev)) i845_update_cursor(crtc, base); else i9xx_update_cursor(crtc, base); -- GitLab From dc41c154ffc30afb7ee7e891140dead26fce5c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 13 Aug 2014 11:57:05 +0300 Subject: [PATCH 0235/5088] drm/i915: Add support for variable cursor size on 845/865 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 845/865 support different cursor sizes as well, albeit a bit differently than later platforms. Add the necessary code to make them work. Untested due to lack of hardware. v2: Warn but accept invalid stride (Chris) Rewrite the cursor size checks for other platforms (Chris) v3: More polish and magic to the cursor size checks (Chris) v4: Moar polish and a comment (Chris) Reviewed-by: Chris Wilson Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 111 +++++++++++++++++++++------ drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 91 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f79c20d49d99..203062e93452 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4128,7 +4128,8 @@ enum punit_power_well { /* Old style CUR*CNTR flags (desktop 8xx) */ #define CURSOR_ENABLE 0x80000000 #define CURSOR_GAMMA_ENABLE 0x40000000 -#define CURSOR_STRIDE_MASK 0x30000000 +#define CURSOR_STRIDE_SHIFT 28 +#define CURSOR_STRIDE(x) ((ffs(x)-9) << CURSOR_STRIDE_SHIFT) /* 256,512,1k,2k */ #define CURSOR_PIPE_CSC_ENABLE (1<<24) #define CURSOR_FORMAT_SHIFT 24 #define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b3fb127131f0..fd15601f6360 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8047,30 +8047,55 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - uint32_t cntl; + uint32_t cntl = 0, size = 0; - if (base != intel_crtc->cursor_base) { - /* On these chipsets we can only modify the base whilst - * the cursor is disabled. - */ - if (intel_crtc->cursor_cntl) { - I915_WRITE(_CURACNTR, 0); - POSTING_READ(_CURACNTR); - intel_crtc->cursor_cntl = 0; + if (base) { + unsigned int width = intel_crtc->cursor_width; + unsigned int height = intel_crtc->cursor_height; + unsigned int stride = roundup_pow_of_two(width) * 4; + + switch (stride) { + default: + WARN_ONCE(1, "Invalid cursor width/stride, width=%u, stride=%u\n", + width, stride); + stride = 256; + /* fallthrough */ + case 256: + case 512: + case 1024: + case 2048: + break; } + cntl |= CURSOR_ENABLE | + CURSOR_GAMMA_ENABLE | + CURSOR_FORMAT_ARGB | + CURSOR_STRIDE(stride); + + size = (height << 12) | width; + } + + if (intel_crtc->cursor_cntl != 0 && + (intel_crtc->cursor_base != base || + intel_crtc->cursor_size != size || + intel_crtc->cursor_cntl != cntl)) { + /* On these chipsets we can only modify the base/size/stride + * whilst the cursor is disabled. + */ + I915_WRITE(_CURACNTR, 0); + POSTING_READ(_CURACNTR); + intel_crtc->cursor_cntl = 0; + } + + if (intel_crtc->cursor_base != base) I915_WRITE(_CURABASE, base); - POSTING_READ(_CURABASE); + + if (intel_crtc->cursor_size != size) { + I915_WRITE(CURSIZE, size); + intel_crtc->cursor_size = size; } - /* XXX width must be 64, stride 256 => 0x00 << 28 */ - cntl = 0; - if (base) - cntl = (CURSOR_ENABLE | - CURSOR_GAMMA_ENABLE | - CURSOR_FORMAT_ARGB); if (intel_crtc->cursor_cntl != cntl) { - I915_WRITE(CURSIZE, (64 << 12) | 64); I915_WRITE(_CURACNTR, cntl); POSTING_READ(_CURACNTR); intel_crtc->cursor_cntl = cntl; @@ -8169,6 +8194,43 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, intel_crtc->cursor_base = base; } +static bool cursor_size_ok(struct drm_device *dev, + uint32_t width, uint32_t height) +{ + if (width == 0 || height == 0) + return false; + + /* + * 845g/865g are special in that they are only limited by + * the width of their cursors, the height is arbitrary up to + * the precision of the register. Everything else requires + * square cursors, limited to a few power-of-two sizes. + */ + if (IS_845G(dev) || IS_I865G(dev)) { + if ((width & 63) != 0) + return false; + + if (width > (IS_845G(dev) ? 64 : 512)) + return false; + + if (height > 1023) + return false; + } else { + switch (width | height) { + case 256: + case 128: + if (IS_GEN2(dev)) + return false; + case 64: + break; + default: + return false; + } + } + + return true; +} + /* * intel_crtc_cursor_set_obj - Set cursor to specified GEM object * @@ -8183,7 +8245,7 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; - unsigned old_width; + unsigned old_width, stride; uint32_t addr; int ret; @@ -8197,14 +8259,13 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc, } /* Check for which cursor types we support */ - if (!((width == 64 && height == 64) || - (width == 128 && height == 128 && !IS_GEN2(dev)) || - (width == 256 && height == 256 && !IS_GEN2(dev)))) { + if (!cursor_size_ok(dev, width, height)) { DRM_DEBUG("Cursor dimension not supported\n"); return -EINVAL; } - if (obj->base.size < width * height * 4) { + stride = roundup_pow_of_two(width) * 4; + if (obj->base.size < stride * height) { DRM_DEBUG_KMS("buffer is too small\n"); ret = -ENOMEM; goto fail; @@ -11797,6 +11858,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_base = ~0; intel_crtc->cursor_cntl = ~0; + intel_crtc->cursor_size = ~0; BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL); @@ -12585,7 +12647,10 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.max_height = 8192; } - if (IS_GEN2(dev)) { + if (IS_845G(dev) || IS_I865G(dev)) { + dev->mode_config.cursor_width = IS_845G(dev) ? 64 : 512; + dev->mode_config.cursor_height = 1023; + } else if (IS_GEN2(dev)) { dev->mode_config.cursor_width = GEN2_CURSOR_WIDTH; dev->mode_config.cursor_height = GEN2_CURSOR_HEIGHT; } else { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 666ca8a044ea..579b1d40f934 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -405,6 +405,7 @@ struct intel_crtc { uint32_t cursor_addr; int16_t cursor_width, cursor_height; uint32_t cursor_cntl; + uint32_t cursor_size; uint32_t cursor_base; struct intel_plane_config plane_config; -- GitLab From 7312e2ddec1ffe4511a85a2814df44e79ded3c1d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 13 Aug 2014 12:14:12 +0100 Subject: [PATCH 0236/5088] drm/i915: Replace __I915__ with typesafe variant Ville pointed out the GCCism __builtin_types_compatible_p() that we could use to replace our heavily casted presumption __I915__ macro that was based on comparing struct sizes. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 --- drivers/gpu/drm/i915/i915_drv.h | 12 ++++++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 04dd6112865e..db56b26a08c9 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1595,9 +1595,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (!drm_core_check_feature(dev, DRIVER_MODESET) && !dev->agp) return -EINVAL; - /* For the ugly agnostic INTEL_INFO macro */ - BUILD_BUG_ON(sizeof(*dev_priv) == sizeof(*dev)); - dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index eb99a109c0bc..2af0071efb38 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2004,8 +2004,16 @@ struct drm_i915_cmd_table { }; /* Note that the (struct drm_i915_private *) cast is just to shut up gcc. */ -#define __I915__(p) ((sizeof(*(p)) == sizeof(struct drm_i915_private)) ? \ - (struct drm_i915_private *)(p) : to_i915(p)) +#define __I915__(p) ({ \ + struct drm_i915_private *__p; \ + if (__builtin_types_compatible_p(typeof(*p), struct drm_i915_private)) \ + __p = (struct drm_i915_private *)p; \ + else if (__builtin_types_compatible_p(typeof(*p), struct drm_device)) \ + __p = to_i915((struct drm_device *)p); \ + else \ + BUILD_BUG(); \ + __p; \ +}) #define INTEL_INFO(p) (&__I915__(p)->info) #define INTEL_DEVID(p) (INTEL_INFO(p)->device_id) -- GitLab From 82e3b8c130f046b7dd1e7898c10e40edb52fee6d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 13 Aug 2014 13:09:46 +0100 Subject: [PATCH 0237/5088] drm/i915: Localise the fbdev console lock frobbing Rather than take and release the console_lock() around a non-existent DRM_I915_FBDEV, move the lock acquisation into the callee where it will be compiled out by the config option entirely. This includes moving the deferred fb_set_suspend() dance and encapsulating it entirely within intel_fbdev.c. v2: Use an integral work item so that we can explicitly flush the work upon suspend/unload. Signed-off-by: Chris Wilson Cc: Daniel Vetter [danvet: Add the flush_work in fbdev_fini per the mailing list discussion. And s/BUG_ON/WARN_ON/ because.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 -- drivers/gpu/drm/i915/i915_drv.c | 28 ++----------------- drivers/gpu/drm/i915/i915_drv.h | 9 +----- drivers/gpu/drm/i915/intel_drv.h | 4 +-- drivers/gpu/drm/i915/intel_fbdev.c | 44 +++++++++++++++++++++++++++++- 5 files changed, 48 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index db56b26a08c9..3f676f904f7e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1350,8 +1350,6 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) goto cleanup_irq; - INIT_WORK(&dev_priv->console_resume_work, intel_console_resume); - intel_modeset_gem_init(dev); /* Always safe in the mode setting case. */ @@ -1864,7 +1862,6 @@ int i915_driver_unload(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) { intel_fbdev_fini(dev); intel_modeset_cleanup(dev); - cancel_work_sync(&dev_priv->console_resume_work); /* * free the memory space allocated for the child device diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ec96f9a9724c..01de97776d81 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -558,9 +558,7 @@ static int i915_drm_freeze(struct drm_device *dev) intel_uncore_forcewake_reset(dev, false); intel_opregion_fini(dev); - console_lock(); - intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED); - console_unlock(); + intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); dev_priv->suspend_count++; @@ -599,18 +597,6 @@ int i915_suspend(struct drm_device *dev, pm_message_t state) return 0; } -void intel_console_resume(struct work_struct *work) -{ - struct drm_i915_private *dev_priv = - container_of(work, struct drm_i915_private, - console_resume_work); - struct drm_device *dev = dev_priv->dev; - - console_lock(); - intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING); - console_unlock(); -} - static int i915_drm_thaw_early(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -681,17 +667,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) intel_opregion_init(dev); - /* - * The console lock can be pretty contented on resume due - * to all the printk activity. Try to keep it out of the hot - * path of resume if possible. - */ - if (console_trylock()) { - intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING); - console_unlock(); - } else { - schedule_work(&dev_priv->console_resume_work); - } + intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false); mutex_lock(&dev_priv->modeset_restore_lock); dev_priv->modeset_restore = MODESET_DONE; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2af0071efb38..541fb6f295bb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1586,14 +1586,9 @@ struct drm_i915_private { #ifdef CONFIG_DRM_I915_FBDEV /* list of fbdev register on this device */ struct intel_fbdev *fbdev; + struct work_struct fbdev_suspend_work; #endif - /* - * The console may be contended at resume, but we don't - * want it to block on it. - */ - struct work_struct console_resume_work; - struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; @@ -2225,8 +2220,6 @@ 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); -extern void intel_console_resume(struct work_struct *work); - /* i915_irq.c */ void i915_queue_hangcheck(struct drm_device *dev); __printf(3, 4) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 579b1d40f934..4ab0d928b819 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -948,7 +948,7 @@ void intel_dvo_init(struct drm_device *dev); extern int intel_fbdev_init(struct drm_device *dev); extern void intel_fbdev_initial_config(struct drm_device *dev); extern void intel_fbdev_fini(struct drm_device *dev); -extern void intel_fbdev_set_suspend(struct drm_device *dev, int state); +extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous); extern void intel_fbdev_output_poll_changed(struct drm_device *dev); extern void intel_fbdev_restore_mode(struct drm_device *dev); #else @@ -965,7 +965,7 @@ static inline void intel_fbdev_fini(struct drm_device *dev) { } -static inline void intel_fbdev_set_suspend(struct drm_device *dev, int state) +static inline void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous) { } diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index f475414671d8..cf052a39558d 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -636,6 +637,15 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, return false; } +static void intel_fbdev_suspend_worker(struct work_struct *work) +{ + intel_fbdev_set_suspend(container_of(work, + struct drm_i915_private, + fbdev_suspend_work)->dev, + FBINFO_STATE_RUNNING, + true); +} + int intel_fbdev_init(struct drm_device *dev) { struct intel_fbdev *ifbdev; @@ -662,6 +672,8 @@ int intel_fbdev_init(struct drm_device *dev) } dev_priv->fbdev = ifbdev; + INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker); + drm_fb_helper_single_add_all_connectors(&ifbdev->helper); return 0; @@ -682,12 +694,14 @@ void intel_fbdev_fini(struct drm_device *dev) if (!dev_priv->fbdev) return; + flush_work(&dev_priv->fbdev_suspend_work); + intel_fbdev_destroy(dev, dev_priv->fbdev); kfree(dev_priv->fbdev); dev_priv->fbdev = NULL; } -void intel_fbdev_set_suspend(struct drm_device *dev, int state) +void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_fbdev *ifbdev = dev_priv->fbdev; @@ -698,6 +712,33 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state) info = ifbdev->helper.fbdev; + if (synchronous) { + /* Flush any pending work to turn the console on, and then + * wait to turn it off. It must be synchronous as we are + * about to suspend or unload the driver. + * + * Note that from within the work-handler, we cannot flush + * ourselves, so only flush outstanding work upon suspend! + */ + if (state != FBINFO_STATE_RUNNING) + flush_work(&dev_priv->fbdev_suspend_work); + console_lock(); + } else { + /* + * The console lock can be pretty contented on resume due + * to all the printk activity. Try to keep it out of the hot + * path of resume if possible. + */ + WARN_ON(state != FBINFO_STATE_RUNNING); + if (!console_trylock()) { + /* Don't block our own workqueue as this can + * be run in parallel with other i915.ko tasks. + */ + schedule_work(&dev_priv->fbdev_suspend_work); + return; + } + } + /* On resume from hibernation: If the object is shmemfs backed, it has * been restored from swap. If the object is stolen however, it will be * full of whatever garbage was left in there. @@ -706,6 +747,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state) memset_io(info->screen_base, 0, info->screen_size); fb_set_suspend(info, state); + console_unlock(); } void intel_fbdev_output_poll_changed(struct drm_device *dev) -- GitLab From e7110b9fb901dcc022afd358386c1be69658af7d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 8 Aug 2014 18:00:39 -0300 Subject: [PATCH 0238/5088] perf top: Don't look for kernel idle symbols in all DSOs The 'top' tool initially supported only kernel symbols, when making it support userspace symbols we forgot to make the symbol filter first check that the DSO is the kernel one. Fix it. Cc: Adrian Hunter Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra c: Stephane Eranian Link: http://lkml.kernel.org/n/tip-54haztkeigmbump5sexxnzhv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 +++- tools/perf/util/symbol.c | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index bde216b2071c..4fb6f726271c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -623,10 +623,12 @@ static void *display_thread(void *arg) return NULL; } -static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) +static int symbol_filter(struct map *map, struct symbol *sym) { const char *name = sym->name; + if (!map->dso->kernel) + return 0; /* * ppc64 uses function descriptors and appends a '.' to the * start of every instruction address. Remove it. diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index f134ec138934..35a8bd56cd15 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -523,6 +523,10 @@ struct process_kallsyms_args { struct dso *dso; }; +/* + * These are symbols in the kernel image, so make sure that + * sym is from a kernel DSO. + */ bool symbol__is_idle(struct symbol *sym) { const char * const idle_symbols[] = { -- GitLab From e0336ed66f5dd974e02b1af4a81bb567a2391e45 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 8 Aug 2014 18:02:41 -0300 Subject: [PATCH 0239/5088] perf tools: Add cpu_startup_entry to the list of kernel idle symbols Cc: Adrian Hunter Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-oh4lrofvrqqv1eyslh7m4rq4@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 35a8bd56cd15..581c56836567 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -531,6 +531,7 @@ bool symbol__is_idle(struct symbol *sym) { const char * const idle_symbols[] = { "cpu_idle", + "cpu_startup_entry", "intel_idle", "default_idle", "native_safe_halt", -- GitLab From ae256fa27118e54b0f093f0cfe2ada28f1704ef3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 11 Aug 2014 10:50:05 +0200 Subject: [PATCH 0240/5088] perf top: Join the display thread on exit We create the display thread, but never join it. It gives the display thread a chance to quit and cleanup properly. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407747014-18394-12-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4fb6f726271c..10fc7e844872 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -965,7 +965,7 @@ static int __cmd_top(struct perf_top *top) param.sched_priority = top->realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { ui__error("Could not set realtime priority.\n"); - goto out_delete; + goto out_join; } } @@ -979,6 +979,8 @@ static int __cmd_top(struct perf_top *top) } ret = 0; +out_join: + pthread_join(thread, NULL); out_delete: perf_session__delete(top->session); top->session = NULL; -- GitLab From 9398c484f8abc8d287cb90f5a33dd43ac26f24ef Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 11 Aug 2014 10:50:02 +0200 Subject: [PATCH 0241/5088] perf tools: Introduce set_term_quiet_input helper function Adding set_term_quiet_input helper to set the terminal quiet, out from 'perf top', used in following patches in 'perf kvm'. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407747014-18394-9-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 10 ++-------- tools/perf/util/util.c | 13 +++++++++++++ tools/perf/util/util.h | 2 ++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 10fc7e844872..e8459e260c3b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -580,20 +580,14 @@ static void *display_thread_tui(void *arg) static void *display_thread(void *arg) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; - struct termios tc, save; + struct termios save; struct perf_top *top = arg; int delay_msecs, c; - tcgetattr(0, &save); - tc = save; - tc.c_lflag &= ~(ICANON | ECHO); - tc.c_cc[VMIN] = 0; - tc.c_cc[VTIME] = 0; - pthread__unblock_sigwinch(); repeat: delay_msecs = top->delay_secs * 1000; - tcsetattr(0, TCSANOW, &tc); + set_term_quiet_input(&save); /* trash return*/ getc(stdin); diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index b82a93cb1694..25822bdf7bbf 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -13,6 +13,7 @@ #include #include #include +#include /* * XXX We need to find a better place for these things... @@ -282,6 +283,18 @@ void get_term_dimensions(struct winsize *ws) ws->ws_col = 80; } +void set_term_quiet_input(struct termios *old) +{ + struct termios tc; + + tcgetattr(0, old); + tc = *old; + tc.c_lflag &= ~(ICANON | ECHO); + tc.c_cc[VMIN] = 0; + tc.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &tc); +} + static void set_tracing_events_path(const char *mountpoint) { snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 03a1ea2266b8..d6a79b1fb28c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -75,6 +75,7 @@ #include #include #include +#include extern const char *graph_line; extern const char *graph_dotted_line; @@ -308,6 +309,7 @@ extern unsigned int page_size; extern int cacheline_size; void get_term_dimensions(struct winsize *ws); +void set_term_quiet_input(struct termios *old); struct parse_tag { char tag; -- GitLab From 4a1a99712a8a13d97e9de818869bf1b88583d6bc Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 11 Aug 2014 10:50:07 +0200 Subject: [PATCH 0242/5088] perf top: Setup signals for terminal output The TUI code setup standard signals handling, while the stdio display code does not. This leads to premature termination of display thread when signal is received and leaving terminal in wrong state. Also adding terminal cleanup at the end of display thread, to ensure we get the old terminal state in case of signal interruption. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407747014-18394-14-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e8459e260c3b..0ab3ea7f7525 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -577,6 +577,20 @@ static void *display_thread_tui(void *arg) return NULL; } +static void display_sig(int sig __maybe_unused) +{ + done = 1; +} + +static void display_setup_sig(void) +{ + signal(SIGSEGV, display_sig); + signal(SIGFPE, display_sig); + signal(SIGINT, display_sig); + signal(SIGQUIT, display_sig); + signal(SIGTERM, display_sig); +} + static void *display_thread(void *arg) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; @@ -584,6 +598,7 @@ static void *display_thread(void *arg) struct perf_top *top = arg; int delay_msecs, c; + display_setup_sig(); pthread__unblock_sigwinch(); repeat: delay_msecs = top->delay_secs * 1000; @@ -614,6 +629,7 @@ static void *display_thread(void *arg) } } + tcsetattr(0, TCSAFLUSH, &save); return NULL; } -- GitLab From d5b4130ae636e1fd0eaaea7152170198c34fbf62 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 11 Aug 2014 10:50:09 +0200 Subject: [PATCH 0243/5088] perf kvm: Fix stdin handling for 'kvm stat live' command Currently the initial ~(ICANON | ECHO) terminal mode is not set, so we dont get stdin data until we press ENTER. Fixing this by early setting of the ~(ICANON | ECHO) mode and leaving this mode for whole life of the command, because canonical mode is not needed. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407747014-18394-16-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 7ccceadcd9f8..ff404750d744 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -885,15 +885,11 @@ static int fd_set_nonblock(int fd) return 0; } -static -int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save) +static int perf_kvm__handle_stdin(void) { int c; - tcsetattr(0, TCSANOW, tc_now); c = getc(stdin); - tcsetattr(0, TCSAFLUSH, tc_save); - if (c == 'q') return 1; @@ -904,7 +900,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) { struct pollfd *pollfds = NULL; int nr_fds, nr_stdin, ret, err = -EINVAL; - struct termios tc, save; + struct termios save; /* live flag must be set first */ kvm->live = true; @@ -919,14 +915,9 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) goto out; } + set_term_quiet_input(&save); init_kvm_event_record(kvm); - tcgetattr(0, &save); - tc = save; - tc.c_lflag &= ~(ICANON | ECHO); - tc.c_cc[VMIN] = 0; - tc.c_cc[VTIME] = 0; - signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); @@ -972,7 +963,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) goto out; if (pollfds[nr_stdin].revents & POLLIN) - done = perf_kvm__handle_stdin(&tc, &save); + done = perf_kvm__handle_stdin(); if (!rc && !done) err = poll(pollfds, nr_fds, 100); @@ -989,6 +980,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) if (kvm->timerfd >= 0) close(kvm->timerfd); + tcsetattr(0, TCSAFLUSH, &save); free(pollfds); return err; } -- GitLab From d177143c3670aa57ee08c73880beb55ee9d8ab7c Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 8 Aug 2014 14:47:21 +0800 Subject: [PATCH 0244/5088] ASoC: fsl_esai: refine esai for TDM support Original driver didn't store the number of slots, just fix the slot number to 2, use this default number to calculate bclk and pins for TX/RX. In this patch, add one parameter for slots, and update the calculation of bclk and pins of TX/RX. Then driver will be compatible with slots > 2 in TDM mode. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 14 +++++++++++--- sound/soc/fsl/fsl_esai.h | 8 ++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 72d154e7dd03..f252370073e5 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -38,6 +38,7 @@ * @fsysclk: system clock source to derive HCK, SCK and FS * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot + * @slots: number of slots * @hck_rate: clock rate of desired HCKx clock * @sck_rate: clock rate of desired SCKx clock * @hck_dir: the direction of HCKx pads @@ -56,6 +57,7 @@ struct fsl_esai { struct clk *fsysclk; u32 fifo_depth; u32 slot_width; + u32 slots; u32 hck_rate[2]; u32 sck_rate[2]; bool hck_dir[2]; @@ -363,6 +365,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); esai_priv->slot_width = slot_width; + esai_priv->slots = slots; return 0; } @@ -510,10 +513,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 width = snd_pcm_format_width(params_format(params)); u32 channels = params_channels(params); + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); u32 bclk, mask, val; int ret; - bclk = params_rate(params) * esai_priv->slot_width * 2; + bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots; ret = fsl_esai_set_bclk(dai, tx, bclk); if (ret) @@ -530,7 +534,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK | (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK); val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) | - (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels)); + (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins)); regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); @@ -565,6 +569,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u8 i, channels = substream->runtime->channels; + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -579,7 +584,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, - tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels)); + tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: @@ -783,6 +788,9 @@ static int fsl_esai_probe(struct platform_device *pdev) /* Set a default slot size */ esai_priv->slot_width = 32; + /* Set a default slot number */ + esai_priv->slots = 2; + /* Set a default master/slave state */ esai_priv->slave_mode = true; diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h index 75e14033e8d8..91a550f4a10d 100644 --- a/sound/soc/fsl/fsl_esai.h +++ b/sound/soc/fsl/fsl_esai.h @@ -130,8 +130,8 @@ #define ESAI_xFCR_RE_WIDTH 4 #define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) #define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) -#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK) -#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK) +#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - x)) & ESAI_xFCR_TE_MASK) +#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - x)) & ESAI_xFCR_RE_MASK) #define ESAI_xFCR_xFR_SHIFT 1 #define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT) #define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT) @@ -272,8 +272,8 @@ #define ESAI_xCR_RE_WIDTH 4 #define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) #define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) -#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK) -#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK) +#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - x)) & ESAI_xCR_TE_MASK) +#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - x)) & ESAI_xCR_RE_MASK) /* * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8 -- GitLab From 5e45187cc94814d2a5324bc18af994efc4fb4f7c Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 13 Aug 2014 16:12:48 +0000 Subject: [PATCH 0245/5088] perf probe: Fix --list option to show events only with uprobe events Current perf probe --list doesn't work if only CONFIG_UPROBE_EVENTS=y because it aborts when it fails to open kprobe_events file before checking uprobe_events file. This fixes --list option to show dynamic events if it can open either kprobe_events or uprobe_events. Only if it failed to open both of them, it shows an error message and aborts. Without this patch, if we run perf probe -l on the kernel configured with CONFIG_KPROBE_EVENTS=n and CONFIG_UPROBE_EVENTS=y, # perf probe -l /sys/kernel/debug/tracing/kprobe_events file does not exist - please rebuild ker Error: Failed to show event list. With this patch, # perf probe -l probe_perf:alloc_event (on alloc_event@lib/traceevent/event-parse.c in /home/fedora/ksrc/linux-3/tools/perf/perf) Changes in v2: - Use strerror_r instead of strerror. Reported-by: Naohiro Aota Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140813161248.26440.84370.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 89 +++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 30 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 9a0a1839a377..50aa7f05ceb1 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1780,10 +1780,11 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) memset(tev, 0, sizeof(*tev)); } -static void print_warn_msg(const char *file, bool is_kprobe) +static void print_open_warning(int err, bool is_kprobe) { + char sbuf[128]; - if (errno == ENOENT) { + if (err == -ENOENT) { const char *config; if (!is_kprobe) @@ -1791,25 +1792,26 @@ static void print_warn_msg(const char *file, bool is_kprobe) else config = "CONFIG_KPROBE_EVENTS"; - pr_warning("%s file does not exist - please rebuild kernel" - " with %s.\n", file, config); - } else - pr_warning("Failed to open %s file: %s\n", file, - strerror(errno)); + pr_warning("%cprobe_events file does not exist" + " - please rebuild kernel with %s.\n", + is_kprobe ? 'k' : 'u', config); + } else if (err == -ENOTSUP) + pr_warning("Debugfs is not mounted.\n"); + else + pr_warning("Failed to open %cprobe_events: %s\n", + is_kprobe ? 'k' : 'u', + strerror_r(-err, sbuf, sizeof(sbuf))); } -static int open_probe_events(const char *trace_file, bool readwrite, - bool is_kprobe) +static int open_probe_events(const char *trace_file, bool readwrite) { char buf[PATH_MAX]; const char *__debugfs; int ret; __debugfs = debugfs_find_mountpoint(); - if (__debugfs == NULL) { - pr_warning("Debugfs is not mounted.\n"); - return -ENOENT; - } + if (__debugfs == NULL) + return -ENOTSUP; ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); if (ret >= 0) { @@ -1820,19 +1822,19 @@ static int open_probe_events(const char *trace_file, bool readwrite, ret = open(buf, O_RDONLY, 0); if (ret < 0) - print_warn_msg(buf, is_kprobe); + ret = -errno; } return ret; } static int open_kprobe_events(bool readwrite) { - return open_probe_events("tracing/kprobe_events", readwrite, true); + return open_probe_events("tracing/kprobe_events", readwrite); } static int open_uprobe_events(bool readwrite) { - return open_probe_events("tracing/uprobe_events", readwrite, false); + return open_probe_events("tracing/uprobe_events", readwrite); } /* Get raw string list of current kprobe_events or uprobe_events */ @@ -1940,27 +1942,47 @@ static int __show_perf_probe_events(int fd, bool is_kprobe) /* List up current perf-probe events */ int show_perf_probe_events(void) { - int fd, ret; + int kp_fd, up_fd, ret; setup_pager(); - fd = open_kprobe_events(false); - - if (fd < 0) - return fd; ret = init_symbol_maps(false); if (ret < 0) return ret; - ret = __show_perf_probe_events(fd, true); - close(fd); + kp_fd = open_kprobe_events(false); + if (kp_fd >= 0) { + ret = __show_perf_probe_events(kp_fd, true); + close(kp_fd); + if (ret < 0) + goto out; + } - fd = open_uprobe_events(false); - if (fd >= 0) { - ret = __show_perf_probe_events(fd, false); - close(fd); + up_fd = open_uprobe_events(false); + if (kp_fd < 0 && up_fd < 0) { + /* Both kprobes and uprobes are disabled, warn it. */ + if (kp_fd == -ENOTSUP && up_fd == -ENOTSUP) + pr_warning("Debugfs is not mounted.\n"); + else if (kp_fd == -ENOENT && up_fd == -ENOENT) + pr_warning("Please rebuild kernel with " + "CONFIG_KPROBE_EVENTS or/and " + "CONFIG_UPROBE_EVENTS.\n"); + else { + char sbuf[128]; + pr_warning("Failed to open kprobe events: %s.\n", + strerror_r(-kp_fd, sbuf, sizeof(sbuf))); + pr_warning("Failed to open uprobe events: %s.\n", + strerror_r(-up_fd, sbuf, sizeof(sbuf))); + } + ret = kp_fd; + goto out; } + if (up_fd >= 0) { + ret = __show_perf_probe_events(up_fd, false); + close(up_fd); + } +out: exit_symbol_maps(); return ret; } @@ -2075,8 +2097,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, else fd = open_kprobe_events(true); - if (fd < 0) + if (fd < 0) { + print_open_warning(fd, !pev->uprobes); return fd; + } + /* Get current event names */ namelist = get_probe_trace_event_names(fd, false); if (!namelist) { @@ -2449,13 +2474,17 @@ int del_perf_probe_events(struct strlist *dellist) /* Get current event names */ kfd = open_kprobe_events(true); - if (kfd < 0) + if (kfd < 0) { + print_open_warning(kfd, true); return kfd; + } namelist = get_probe_trace_event_names(kfd, true); ufd = open_uprobe_events(true); - if (ufd >= 0) + if (ufd < 0) + print_open_warning(ufd, false); + else unamelist = get_probe_trace_event_names(ufd, true); if (namelist == NULL && unamelist == NULL) -- GitLab From 467ec08567483e3868f240b1ee03808970e06388 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 13 Aug 2014 16:12:50 +0000 Subject: [PATCH 0246/5088] perf probe: Fix --del option to delete events only with uprobe events Current perf probe --del doesn't work if only CONFIG_UPROBE_EVENTS=y because it aborts when it fails to open kprobe_events file before checking uprobe_events file. This fixes --del option to delete dynamic events if it can open either kprobe_events or uprobe_events. Only if it failed to open both of them, it shows an error message and aborts. Without this patch, if we run perf probe -d on the kernel configured with CONFIG_KPROBE_EVENTS=n and CONFIG_UPROBE_EVENTS=y, # perf probe -d \* kprobe_events file does not exist - please rebuild kernel with CONFIG_KPROBE_EVENTS. Error: Failed to delete events. With this patch, # perf probe -d \* Removed event: probe_perf:alloc_event Changes in v2: - Use strerror_r instead of strerror. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140813161250.26440.24028.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 49 +++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 50aa7f05ceb1..443225cb62f7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1803,6 +1803,23 @@ static void print_open_warning(int err, bool is_kprobe) strerror_r(-err, sbuf, sizeof(sbuf))); } +static void print_both_open_warning(int kerr, int uerr) +{ + /* Both kprobes and uprobes are disabled, warn it. */ + if (kerr == -ENOTSUP && uerr == -ENOTSUP) + pr_warning("Debugfs is not mounted.\n"); + else if (kerr == -ENOENT && uerr == -ENOENT) + pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS " + "or/and CONFIG_UPROBE_EVENTS.\n"); + else { + char sbuf[128]; + pr_warning("Failed to open kprobe events: %s.\n", + strerror_r(-kerr, sbuf, sizeof(sbuf))); + pr_warning("Failed to open uprobe events: %s.\n", + strerror_r(-uerr, sbuf, sizeof(sbuf))); + } +} + static int open_probe_events(const char *trace_file, bool readwrite) { char buf[PATH_MAX]; @@ -1960,20 +1977,7 @@ int show_perf_probe_events(void) up_fd = open_uprobe_events(false); if (kp_fd < 0 && up_fd < 0) { - /* Both kprobes and uprobes are disabled, warn it. */ - if (kp_fd == -ENOTSUP && up_fd == -ENOTSUP) - pr_warning("Debugfs is not mounted.\n"); - else if (kp_fd == -ENOENT && up_fd == -ENOENT) - pr_warning("Please rebuild kernel with " - "CONFIG_KPROBE_EVENTS or/and " - "CONFIG_UPROBE_EVENTS.\n"); - else { - char sbuf[128]; - pr_warning("Failed to open kprobe events: %s.\n", - strerror_r(-kp_fd, sbuf, sizeof(sbuf))); - pr_warning("Failed to open uprobe events: %s.\n", - strerror_r(-up_fd, sbuf, sizeof(sbuf))); - } + print_both_open_warning(kp_fd, up_fd); ret = kp_fd; goto out; } @@ -2474,19 +2478,18 @@ int del_perf_probe_events(struct strlist *dellist) /* Get current event names */ kfd = open_kprobe_events(true); - if (kfd < 0) { - print_open_warning(kfd, true); - return kfd; - } + if (kfd >= 0) + namelist = get_probe_trace_event_names(kfd, true); - namelist = get_probe_trace_event_names(kfd, true); ufd = open_uprobe_events(true); - - if (ufd < 0) - print_open_warning(ufd, false); - else + if (ufd >= 0) unamelist = get_probe_trace_event_names(ufd, true); + if (kfd < 0 && ufd < 0) { + print_both_open_warning(kfd, ufd); + goto error; + } + if (namelist == NULL && unamelist == NULL) goto error; -- GitLab From 86998dda5d244f4b1b994dfe34a677f3b70cfdd3 Mon Sep 17 00:00:00 2001 From: Alex Snast Date: Wed, 13 Aug 2014 18:42:40 +0300 Subject: [PATCH 0247/5088] perf trace: Add beautifier for mremap flags param MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ~/devel/kernel/tools/perf(branch:master*) » sudo ./perf trace ~/mremap_test 0.543 ( 0.003 ms): mprotect(start: 0x600000, len: 4096, prot: READ ) = 0 0.550 ( 0.003 ms): mprotect(start: 0x7f441260d000, len: 4096, prot: READ) = 0 0.561 ( 0.010 ms): munmap(addr: 0x7f44125e2000, len: 165572 ) = 0 0.595 ( 0.012 ms): mmap(len: 12288, prot: READ|WRITE, flags: SHARED|ANONYMOUS|LOCKED, fd: -1) = 0x12608000 0.603 ( 0.006 ms): mremap(addr: 0x7f4412608000, old_len: 4096, new_len: 4096, flags: MAYMOVE|FIXED, new_addr: 0x7f16da295000) = 0xda295000 0.608 ( 0.003 ms): mremap(addr: 0x7f441260a000, old_len: 4096, new_len: 4096, flags: MAYMOVE|FIXED, new_addr: 0x7f16da297000) = 0xda297000 0.612 ( 0.003 ms): mremap(addr: 0x7f4412609000, old_len: 4096, new_len: 4096, flags: MAYMOVE|FIXED, new_addr: 0x7f16da296000) = 0xda296000 0.619 ( 0.000 ms): exit_group( Signed-off-by: Alex Snast Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407944560-26924-1-git-send-email-asnast@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 36ae51d61be2..20fac5083771 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -402,6 +402,31 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags +static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, + struct syscall_arg *arg) +{ + int printed = 0, flags = arg->val; + +#define P_MREMAP_FLAG(n) \ + if (flags & MREMAP_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ + flags &= ~MREMAP_##n; \ + } + + P_MREMAP_FLAG(MAYMOVE); +#ifdef MREMAP_FIXED + P_MREMAP_FLAG(FIXED); +#endif +#undef P_MREMAP_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} + +#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags + static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, struct syscall_arg *arg) { @@ -1004,6 +1029,7 @@ static struct syscall_fmt { [2] = SCA_MMAP_PROT, /* prot */ }, }, { .name = "mremap", .hexret = true, .arg_scnprintf = { [0] = SCA_HEX, /* addr */ + [3] = SCA_MREMAP_FLAGS, /* flags */ [4] = SCA_HEX, /* new_addr */ }, }, { .name = "munlock", .errmsg = true, .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, -- GitLab From a5b0153c880c2775bf5bdd78306f0a47e860ea04 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 12 Aug 2014 18:04:28 +0300 Subject: [PATCH 0248/5088] perf tools: Fix CLOEXEC probe for perf_event_paranoid == 2 With /proc/sys/kernel/perf_event_paranoid set to 2, the probe of PERF_FLAG_FD_CLOEXEC would fail. Fix by excluding kernel profiling from the probe event. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Acked-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1407855871-15024-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cloexec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index 5073c01af618..000047cb3fee 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c @@ -11,6 +11,7 @@ static int perf_flag_probe(void) struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_CLOCK, + .exclude_kernel = 1, }; int fd; int err; -- GitLab From c6fa35659c5fae5f9aeb6874b177baeb2adbc02e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 12 Aug 2014 18:04:29 +0300 Subject: [PATCH 0249/5088] perf tools: Fix one of the probe events to exclude kernel When probing the kernel API the kernel should be excluded otherwise the probe will fail for users with insufficient privilege to profile the kernel. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Acked-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1407855871-15024-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/record.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index fe8079edbdc1..58267a85705f 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -47,7 +47,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) static bool perf_probe_api(setup_probe_fn_t fn) { - const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL}; + const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL}; struct cpu_map *cpus; int cpu, ret, i = 0; -- GitLab From 46ec69add5df60310147ce3ce01a662053d82a1e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 12 Aug 2014 18:04:30 +0300 Subject: [PATCH 0250/5088] perf tools: Fix probing the kernel API with cpu-wide events Fall back to probing with the current pid if cpu-wide probing fails. This primarily affects the setting of comm_exec flag when the user is un-privileged and /proc/sys/kernel/perf_event_paranoid > 0. The change to comm_exec can be observed by using -vv with perf record and a kernel that supports comm_exec. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1407855871-15024-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/record.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 58267a85705f..e778afda0fb9 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -14,6 +14,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) struct perf_evsel *evsel; unsigned long flags = perf_event_open_cloexec_flag(); int err = -EAGAIN, fd; + static pid_t pid = -1; evlist = perf_evlist__new(); if (!evlist) @@ -24,14 +25,22 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) evsel = perf_evlist__first(evlist); - fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags); - if (fd < 0) - goto out_delete; + while (1) { + fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags); + if (fd < 0) { + if (pid == -1 && errno == EACCES) { + pid = 0; + continue; + } + goto out_delete; + } + break; + } close(fd); fn(evsel); - fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags); + fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags); if (fd < 0) { if (errno == EINVAL) err = -EINVAL; @@ -201,6 +210,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) struct perf_evsel *evsel; int err, fd, cpu; bool ret = false; + pid_t pid = -1; temp_evlist = perf_evlist__new(); if (!temp_evlist) @@ -221,12 +231,20 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) cpu = evlist->cpus->map[0]; } - fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, - perf_event_open_cloexec_flag()); - if (fd >= 0) { - close(fd); - ret = true; + while (1) { + fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, + perf_event_open_cloexec_flag()); + if (fd < 0) { + if (pid == -1 && errno == EACCES) { + pid = 0; + continue; + } + goto out_delete; + } + break; } + close(fd); + ret = true; out_delete: perf_evlist__delete(temp_evlist); -- GitLab From f6edb53c4993ffe92ce521fb449d1c146cea6ec2 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 12 Aug 2014 18:04:31 +0300 Subject: [PATCH 0251/5088] perf tools: Prefer to use a cpu-wide event for probing CLOEXEC When doing a system-wide trace with Intel PT, the jump label set up as a result of probing CLOEXEC gets reset while the trace is running. That causes an Intel PT decoding error because the object code (obtained from /proc/kcore) does not match the running code at that point. While we can't expect there never to be jump label changes, we can avoid cases that the perf tool itself creates. The problem is avoided by first trying a cpu-wide event (pid = -1) for probing the PERF_FLAG_FD_CLOEXEC flag and falling back to an event for the current process (pid = 0). Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1407855871-15024-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cloexec.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index 000047cb3fee..4945aa56a017 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c @@ -1,3 +1,4 @@ +#include #include "util.h" #include "../perf.h" #include "cloexec.h" @@ -15,10 +16,23 @@ static int perf_flag_probe(void) }; int fd; int err; + int cpu; + pid_t pid = -1; - /* check cloexec flag */ - fd = sys_perf_event_open(&attr, 0, -1, -1, - PERF_FLAG_FD_CLOEXEC); + cpu = sched_getcpu(); + if (cpu < 0) + cpu = 0; + + while (1) { + /* check cloexec flag */ + fd = sys_perf_event_open(&attr, pid, cpu, -1, + PERF_FLAG_FD_CLOEXEC); + if (fd < 0 && pid == -1 && errno == EACCES) { + pid = 0; + continue; + } + break; + } err = errno; if (fd >= 0) { @@ -31,7 +45,7 @@ static int perf_flag_probe(void) err, strerror(err)); /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ - fd = sys_perf_event_open(&attr, 0, -1, -1, 0); + fd = sys_perf_event_open(&attr, pid, cpu, -1, 0); err = errno; if (WARN_ONCE(fd < 0 && err != EBUSY, -- GitLab From 6cc870f09da4d50722bc1caa27cad51733ce36f6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:33 +0900 Subject: [PATCH 0252/5088] perf script: Fix possible memory leaks Some paths in perf script don't call perf_session__delete() after creating a new session. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-2-git-send-email-namhyung@kernel.org [ Saved errno value before calling perror(), as pointed out by Adrian Hunter ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 868c17d09762..c84d723e0484 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1471,12 +1471,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) bool show_full_info = false; bool header = false; bool header_only = false; + bool script_started = false; char *rec_script_path = NULL; char *rep_script_path = NULL; struct perf_session *session; char *script_path = NULL; const char **__argv; - int i, j, err; + int i, j, err = 0; struct perf_script script = { .tool = { .sample = process_sample_event, @@ -1730,14 +1731,15 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) if (header || header_only) { perf_session__fprintf_info(session, stdout, show_full_info); if (header_only) - return 0; + goto out_delete; } script.session = session; if (cpu_list) { - if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) - return -1; + err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); + if (err < 0) + goto out_delete; } if (!no_callchain) @@ -1752,53 +1754,60 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) if (output_set_by_user()) { fprintf(stderr, "custom fields not supported for generated scripts"); - return -1; + err = -EINVAL; + goto out_delete; } input = open(file.path, O_RDONLY); /* input_name */ if (input < 0) { + err = -errno; perror("failed to open file"); - return -1; + goto out_delete; } err = fstat(input, &perf_stat); if (err < 0) { perror("failed to stat file"); - return -1; + goto out_delete; } if (!perf_stat.st_size) { fprintf(stderr, "zero-sized file, nothing to do!\n"); - return 0; + goto out_delete; } scripting_ops = script_spec__lookup(generate_script_lang); if (!scripting_ops) { fprintf(stderr, "invalid language specifier"); - return -1; + err = -ENOENT; + goto out_delete; } err = scripting_ops->generate_script(session->tevent.pevent, "perf-script"); - goto out; + goto out_delete; } if (script_name) { err = scripting_ops->start_script(script_name, argc, argv); if (err) - goto out; + goto out_delete; pr_debug("perf script started with script %s\n\n", script_name); + script_started = true; } err = perf_session__check_output_opt(session); if (err < 0) - goto out; + goto out_delete; err = __cmd_script(&script); +out_delete: perf_session__delete(session); - cleanup_scripting(); + + if (script_started) + cleanup_scripting(); out: return err; } -- GitLab From e96c674fe2c228fd5c16fd7a7607c60dea4cdaa2 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:34 +0900 Subject: [PATCH 0253/5088] perf symbols: Fix a memory leak in vmlinux_path__init() When uname() failed, it should free vmlinux_path. Acked-by: Jiri Olsa Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 581c56836567..009a9d064f11 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1772,7 +1772,7 @@ static int vmlinux_path__init(void) return 0; if (uname(&uts) < 0) - return -1; + goto out_fail; snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); -- GitLab From fa10f316d59f39020d19d3f4a323598d05afa65c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:35 +0900 Subject: [PATCH 0254/5088] perf annotate: Move session handling out of __cmd_annotate() This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init(). Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 75 +++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 952b5ece6740..c0464dc38057 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -36,7 +36,8 @@ struct perf_annotate { struct perf_tool tool; - bool force, use_tui, use_stdio, use_gtk; + struct perf_session *session; + bool use_tui, use_stdio, use_gtk; bool full_paths; bool print_line; bool skip_missing; @@ -188,18 +189,9 @@ static void hists__find_annotations(struct hists *hists, static int __cmd_annotate(struct perf_annotate *ann) { int ret; - struct perf_session *session; + struct perf_session *session = ann->session; struct perf_evsel *pos; u64 total_nr_samples; - struct perf_data_file file = { - .path = input_name, - .mode = PERF_DATA_MODE_READ, - .force = ann->force, - }; - - session = perf_session__new(&file, false, &ann->tool); - if (session == NULL) - return -ENOMEM; machines__set_symbol_filter(&session->machines, symbol__annotate_init); @@ -207,22 +199,22 @@ static int __cmd_annotate(struct perf_annotate *ann) ret = perf_session__cpu_bitmap(session, ann->cpu_list, ann->cpu_bitmap); if (ret) - goto out_delete; + goto out; } if (!objdump_path) { ret = perf_session_env__lookup_objdump(&session->header.env); if (ret) - goto out_delete; + goto out; } ret = perf_session__process_events(session, &ann->tool); if (ret) - goto out_delete; + goto out; if (dump_trace) { perf_session__fprintf_nr_events(session, stdout); - goto out_delete; + goto out; } if (verbose > 3) @@ -250,8 +242,8 @@ static int __cmd_annotate(struct perf_annotate *ann) } if (total_nr_samples == 0) { - ui__error("The %s file has no samples!\n", file.path); - goto out_delete; + ui__error("The %s file has no samples!\n", session->file->path); + goto out; } if (use_browser == 2) { @@ -261,24 +253,12 @@ static int __cmd_annotate(struct perf_annotate *ann) "perf_gtk__show_annotations"); if (show_annotations == NULL) { ui__error("GTK browser not found!\n"); - goto out_delete; + goto out; } show_annotations(); } -out_delete: - /* - * Speed up the exit process, for large files this can - * take quite a while. - * - * XXX Enable this when using valgrind or if we ever - * librarize this command. - * - * Also experiment with obstacks to see how much speed - * up we'll get here. - * - * perf_session__delete(session); - */ +out: return ret; } @@ -301,6 +281,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) .ordering_requires_timestamps = true, }, }; + struct perf_data_file file = { + .path = input_name, + .mode = PERF_DATA_MODE_READ, + }; const struct option options[] = { OPT_STRING('i', "input", &input_name, "file", "input file name"), @@ -308,7 +292,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) "only consider symbols in these dsos"), OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol", "symbol to annotate"), - OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"), + OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, @@ -341,6 +325,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) "Show event group information together"), OPT_END() }; + int ret; argc = parse_options(argc, argv, options, annotate_usage, 0); @@ -353,11 +338,16 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) setup_browser(true); + annotate.session = perf_session__new(&file, false, &annotate.tool); + if (annotate.session == NULL) + return -ENOMEM; + symbol_conf.priv_size = sizeof(struct annotation); symbol_conf.try_vmlinux_path = true; - if (symbol__init() < 0) - return -1; + ret = symbol__init(); + if (ret < 0) + goto out_delete; if (setup_sorting() < 0) usage_with_options(annotate_usage, options); @@ -373,5 +363,20 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) annotate.sym_hist_filter = argv[0]; } - return __cmd_annotate(&annotate); + ret = __cmd_annotate(&annotate); + +out_delete: + /* + * Speed up the exit process, for large files this can + * take quite a while. + * + * XXX Enable this when using valgrind or if we ever + * librarize this command. + * + * Also experiment with obstacks to see how much speed + * up we'll get here. + * + * perf_session__delete(session); + */ + return ret; } -- GitLab From e3ed75bb537a860a375ca1e09ad1b87c707f1636 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:36 +0900 Subject: [PATCH 0255/5088] perf buildid-cache: Move session handling into cmd_buildid_cache() This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init(). Acked-by: Jiri Olsa Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-buildid-cache.c | 35 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 2a2c78f80876..d91bfa6632e8 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -246,20 +246,9 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused) return true; } -static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp) +static int build_id_cache__fprintf_missing(struct perf_session *session, FILE *fp) { - struct perf_data_file file = { - .path = filename, - .mode = PERF_DATA_MODE_READ, - .force = force, - }; - struct perf_session *session = perf_session__new(&file, false, NULL); - if (session == NULL) - return -1; - perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0); - perf_session__delete(session); - return 0; } @@ -303,6 +292,11 @@ int cmd_buildid_cache(int argc, const char **argv, *update_name_list_str = NULL, *kcore_filename; + struct perf_data_file file = { + .mode = PERF_DATA_MODE_READ, + }; + struct perf_session *session = NULL; + const struct option buildid_cache_options[] = { OPT_STRING('a', "add", &add_name_list_str, "file list", "file(s) to add"), @@ -326,8 +320,17 @@ int cmd_buildid_cache(int argc, const char **argv, argc = parse_options(argc, argv, buildid_cache_options, buildid_cache_usage, 0); + if (missing_filename) { + file.path = missing_filename; + file.force = force; + + session = perf_session__new(&file, false, NULL); + if (session == NULL) + return -1; + } + if (symbol__init() < 0) - return -1; + goto out; setup_pager(); @@ -370,7 +373,7 @@ int cmd_buildid_cache(int argc, const char **argv, } if (missing_filename) - ret = build_id_cache__fprintf_missing(missing_filename, force, stdout); + ret = build_id_cache__fprintf_missing(session, stdout); if (update_name_list_str) { list = strlist__new(true, update_name_list_str); @@ -394,5 +397,9 @@ int cmd_buildid_cache(int argc, const char **argv, build_id_cache__add_kcore(kcore_filename, debugdir, force)) pr_warning("Couldn't add %s\n", kcore_filename); +out: + if (session) + perf_session__delete(session); + return ret; } -- GitLab From 1cb8bdcca0e2f738a492c3857568cf34ba4a4373 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:37 +0900 Subject: [PATCH 0256/5088] perf inject: Move session handling out of __cmd_inject() This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init(). Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-6-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index ee875cca13b1..18eaefd3cd0c 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -23,6 +23,7 @@ struct perf_inject { struct perf_tool tool; + struct perf_session *session; bool build_ids; bool sched_stat; const char *input_name; @@ -340,12 +341,8 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel, static int __cmd_inject(struct perf_inject *inject) { - struct perf_session *session; int ret = -EINVAL; - struct perf_data_file file = { - .path = inject->input_name, - .mode = PERF_DATA_MODE_READ, - }; + struct perf_session *session = inject->session; struct perf_data_file *file_out = &inject->output; signal(SIGINT, sig_handler); @@ -357,10 +354,6 @@ static int __cmd_inject(struct perf_inject *inject) inject->tool.tracing_data = perf_event__repipe_tracing_data; } - session = perf_session__new(&file, true, &inject->tool); - if (session == NULL) - return -ENOMEM; - if (inject->build_ids) { inject->tool.sample = perf_event__inject_buildid; } else if (inject->sched_stat) { @@ -396,8 +389,6 @@ static int __cmd_inject(struct perf_inject *inject) perf_session__write_header(session, session->evlist, file_out->fd, true); } - perf_session__delete(session); - return ret; } @@ -427,6 +418,11 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .mode = PERF_DATA_MODE_WRITE, }, }; + struct perf_data_file file = { + .mode = PERF_DATA_MODE_READ, + }; + int ret; + const struct option options[] = { OPT_BOOLEAN('b', "build-ids", &inject.build_ids, "Inject build-ids into the output stream"), @@ -461,8 +457,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) return -1; } + file.path = inject.input_name; + inject.session = perf_session__new(&file, true, &inject.tool); + if (inject.session == NULL) + return -ENOMEM; + if (symbol__init() < 0) return -1; - return __cmd_inject(&inject); + ret = __cmd_inject(&inject); + + perf_session__delete(inject.session); + + return ret; } -- GitLab From 2b2b2c68c64fb9db392940b42355944064f2a4ca Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:38 +0900 Subject: [PATCH 0257/5088] perf kmem: Move session handling out of __cmd_kmem() This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init(). Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-7-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kmem.c | 49 ++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 84b82397a28e..349d9b46098e 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -405,10 +405,9 @@ static void sort_result(void) __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); } -static int __cmd_kmem(void) +static int __cmd_kmem(struct perf_session *session) { int err = -EINVAL; - struct perf_session *session; const struct perf_evsel_str_handler kmem_tracepoints[] = { { "kmem:kmalloc", perf_evsel__process_alloc_event, }, { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, }, @@ -417,31 +416,22 @@ static int __cmd_kmem(void) { "kmem:kfree", perf_evsel__process_free_event, }, { "kmem:kmem_cache_free", perf_evsel__process_free_event, }, }; - struct perf_data_file file = { - .path = input_name, - .mode = PERF_DATA_MODE_READ, - }; - - session = perf_session__new(&file, false, &perf_kmem); - if (session == NULL) - return -ENOMEM; if (!perf_session__has_traces(session, "kmem record")) - goto out_delete; + goto out; if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) { pr_err("Initializing perf session tracepoint handlers failed\n"); - return -1; + goto out; } setup_pager(); err = perf_session__process_events(session, &perf_kmem); if (err != 0) - goto out_delete; + goto out; sort_result(); print_result(session); -out_delete: - perf_session__delete(session); +out: return err; } @@ -688,29 +678,46 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) NULL, NULL }; + struct perf_session *session; + struct perf_data_file file = { + .path = input_name, + .mode = PERF_DATA_MODE_READ, + }; + int ret = -1; + argc = parse_options_subcommand(argc, argv, kmem_options, kmem_subcommands, kmem_usage, 0); if (!argc) usage_with_options(kmem_usage, kmem_options); - symbol__init(); - if (!strncmp(argv[0], "rec", 3)) { + symbol__init(); return __cmd_record(argc, argv); - } else if (!strcmp(argv[0], "stat")) { + } + + session = perf_session__new(&file, false, &perf_kmem); + if (session == NULL) + return -ENOMEM; + + symbol__init(); + + if (!strcmp(argv[0], "stat")) { if (cpu__setup_cpunode_map()) - return -1; + goto out_delete; if (list_empty(&caller_sort)) setup_sorting(&caller_sort, default_sort_order); if (list_empty(&alloc_sort)) setup_sorting(&alloc_sort, default_sort_order); - return __cmd_kmem(); + ret = __cmd_kmem(session); } else usage_with_options(kmem_usage, kmem_options); - return 0; +out_delete: + perf_session__delete(session); + + return ret; } -- GitLab From 14d37f38e956ba0dd4f2206f68534eb418ecd905 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:39 +0900 Subject: [PATCH 0258/5088] perf kvm: Move call to symbol__init() after creating session This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init(). Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-8-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index ff404750d744..7f2b55513863 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1064,6 +1064,8 @@ static int read_events(struct perf_kvm_stat *kvm) return -EINVAL; } + symbol__init(); + if (!perf_session__has_traces(kvm->session, "kvm record")) return -EINVAL; @@ -1193,8 +1195,6 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv) NULL }; - symbol__init(); - if (argc) { argc = parse_options(argc, argv, kvm_events_report_options, -- GitLab From 6fd6c6b462c55f33c20f38051f1116dc52054d67 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:40 +0900 Subject: [PATCH 0259/5088] perf lock: Move call to symbol__init() after creating session This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init(). Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-9-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-lock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index c8122d323621..d73580b39908 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -865,6 +865,8 @@ static int __cmd_report(bool display_info) return -ENOMEM; } + symbol__init(); + if (!perf_session__has_traces(session, "lock record")) goto out_delete; @@ -974,7 +976,6 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) unsigned int i; int rc = 0; - symbol__init(); for (i = 0; i < LOCKHASH_SIZE; i++) INIT_LIST_HEAD(lockhash_table + i); -- GitLab From 0493410612486cadaa4e076caf4df3fa9cd20fde Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:41 +0900 Subject: [PATCH 0260/5088] perf sched: Move call to symbol__init() after creating session This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init(). Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-10-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 7c16aeb6b675..dcd9ebf5a7df 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1462,6 +1462,8 @@ static int perf_sched__read_events(struct perf_sched *sched, return -1; } + symbol__init(); + if (perf_session__set_tracepoints_handlers(session, handlers)) goto out_delete; @@ -1747,7 +1749,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) if (!strcmp(argv[0], "script")) return cmd_script(argc, argv, prefix); - symbol__init(); if (!strncmp(argv[0], "rec", 3)) { return __cmd_record(argc, argv); } else if (!strncmp(argv[0], "lat", 3)) { -- GitLab From 38520dc31206bae1dc811ddd59ccea3a6536784d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:42 +0900 Subject: [PATCH 0261/5088] perf script: Move call to symbol__init() after creating session This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init(). Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-11-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index c84d723e0484..9ca7a2d03f17 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1719,8 +1719,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) exit(-1); } - if (symbol__init() < 0) - return -1; if (!script_name) setup_pager(); @@ -1734,6 +1732,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) goto out_delete; } + if (symbol__init() < 0) + goto out_delete; + script.session = session; if (cpu_list) { -- GitLab From dc5c8190b800dc59eff6bb2aa47ea749712197df Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:43 +0900 Subject: [PATCH 0262/5088] perf timechart: Move call to symbol__init() after creating session This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init(). Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-12-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-timechart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 912e3b5bb22b..df3b1c5ae7b9 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1607,6 +1607,8 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) if (session == NULL) return -ENOMEM; + symbol__init(); + (void)perf_header__process_sections(&session->header, perf_data_file__fd(session->file), tchart, @@ -1982,8 +1984,6 @@ int cmd_timechart(int argc, const char **argv, return -1; } - symbol__init(); - if (argc && !strncmp(argv[0], "rec", 3)) { argc = parse_options(argc, argv, record_options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); -- GitLab From cb2ffae241cfdd6d90acb7ec5f52ad8401885dd2 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:44 +0900 Subject: [PATCH 0263/5088] perf trace: Move call to symbol__init() after creating session This is a preparation of fixing dso__load_kernel_sym(). It needs a session info before calling symbol__init(). Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1407825645-24586-13-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 20fac5083771..8a83bd835327 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2241,13 +2241,13 @@ static int trace__replay(struct trace *trace) /* add tid to output */ trace->multiple_threads = true; - if (symbol__init() < 0) - return -1; - session = perf_session__new(&file, false, &trace->tool); if (session == NULL) return -ENOMEM; + if (symbol__init() < 0) + goto out; + trace->host = &session->machines.host; err = perf_session__set_tracepoints_handlers(session, handlers); -- GitLab From 0a7e6d1b6844bec2d6817615a693c7fce447b80d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 15:40:45 +0900 Subject: [PATCH 0264/5088] perf tools: Check recorded kernel version when finding vmlinux Currently vmlinux_path__init() only tries to find vmlinux file from current directory, /boot and some canonical directories with version number of the running kernel. This can be a problem when reporting old data recorded on a kernel version not running currently. We can use --symfs option for this but it's annoying for user to do it always. As we already have the info in the perf.data file, it can be changed to use it for the search automatically. Before: $ perf report ... # Samples: 4K of event 'cpu-clock' # Event count (approx.): 1067250000 # # Overhead Command Shared Object Symbol # ........ .......... ................. .............................. 71.87% swapper [kernel.kallsyms] [k] recover_probed_instruction After: # Overhead Command Shared Object Symbol # ........ .......... ................. .................... 71.87% swapper [kernel.kallsyms] [k] native_safe_halt This requires to change signature of symbol__init() to receive struct perf_session_env *. Reported-by: Minchan Kim Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Minchan Kim Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1407825645-24586-14-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-buildid-cache.c | 2 +- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-kmem.c | 4 ++-- tools/perf/builtin-kvm.c | 4 ++-- tools/perf/builtin-lock.c | 2 +- tools/perf/builtin-mem.c | 2 +- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-script.c | 2 +- tools/perf/builtin-timechart.c | 2 +- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 4 ++-- tools/perf/tests/builtin-test.c | 2 +- tools/perf/util/probe-event.c | 2 +- tools/perf/util/symbol.c | 26 +++++++++++++++++--------- tools/perf/util/symbol.h | 3 ++- 19 files changed, 39 insertions(+), 30 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index c0464dc38057..d4da6929597f 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -345,7 +345,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) symbol_conf.priv_size = sizeof(struct annotation); symbol_conf.try_vmlinux_path = true; - ret = symbol__init(); + ret = symbol__init(&annotate.session->header.env); if (ret < 0) goto out_delete; diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index d91bfa6632e8..ac5838e0b1bd 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -329,7 +329,7 @@ int cmd_buildid_cache(int argc, const char **argv, return -1; } - if (symbol__init() < 0) + if (symbol__init(session ? &session->header.env : NULL) < 0) goto out; setup_pager(); diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index c10cc44bae19..190d0b6b28cc 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -1143,7 +1143,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) argc = parse_options(argc, argv, options, diff_usage, 0); - if (symbol__init() < 0) + if (symbol__init(NULL) < 0) return -1; if (data_init(argc, argv) < 0) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 18eaefd3cd0c..3a62b6b3c8fd 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -462,7 +462,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) if (inject.session == NULL) return -ENOMEM; - if (symbol__init() < 0) + if (symbol__init(&inject.session->header.env) < 0) return -1; ret = __cmd_inject(&inject); diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 349d9b46098e..23762187a219 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -692,7 +692,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) usage_with_options(kmem_usage, kmem_options); if (!strncmp(argv[0], "rec", 3)) { - symbol__init(); + symbol__init(NULL); return __cmd_record(argc, argv); } @@ -700,7 +700,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) if (session == NULL) return -ENOMEM; - symbol__init(); + symbol__init(&session->header.env); if (!strcmp(argv[0], "stat")) { if (cpu__setup_cpunode_map()) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 7f2b55513863..14d03edc81c2 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1064,7 +1064,7 @@ static int read_events(struct perf_kvm_stat *kvm) return -EINVAL; } - symbol__init(); + symbol__init(&kvm->session->header.env); if (!perf_session__has_traces(kvm->session, "kvm record")) return -EINVAL; @@ -1314,7 +1314,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, kvm->opts.target.uid_str = NULL; kvm->opts.target.uid = UINT_MAX; - symbol__init(); + symbol__init(NULL); disable_buildid_cache(); use_browser = 0; diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index d73580b39908..92790ed7af45 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -865,7 +865,7 @@ static int __cmd_report(bool display_info) return -ENOMEM; } - symbol__init(); + symbol__init(&session->header.env); if (!perf_session__has_traces(session, "lock record")) goto out_delete; diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 80e57c84adef..8b4a87fe3858 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -133,7 +133,7 @@ static int report_raw_events(struct perf_mem *mem) goto out_delete; } - if (symbol__init() < 0) + if (symbol__init(&session->header.env) < 0) return -1; printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ca0251e8470d..4db670d4b8da 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -908,7 +908,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) usage_with_options(record_usage, record_options); } - symbol__init(); + symbol__init(NULL); if (symbol_conf.kptr_restrict) pr_warning( diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 041e93da13e4..b9e0fcac4d71 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -798,7 +798,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) } } - if (symbol__init() < 0) + if (symbol__init(&session->header.env) < 0) goto error; if (argc) { diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index dcd9ebf5a7df..f5874a27b346 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1462,7 +1462,7 @@ static int perf_sched__read_events(struct perf_sched *sched, return -1; } - symbol__init(); + symbol__init(&session->header.env); if (perf_session__set_tracepoints_handlers(session, handlers)) goto out_delete; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 9ca7a2d03f17..37d2b608d388 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1732,7 +1732,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) goto out_delete; } - if (symbol__init() < 0) + if (symbol__init(&session->header.env) < 0) goto out_delete; script.session = session; diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index df3b1c5ae7b9..48eea6cd2f5b 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1607,7 +1607,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) if (session == NULL) return -ENOMEM; - symbol__init(); + symbol__init(&session->header.env); (void)perf_header__process_sections(&session->header, perf_data_file__fd(session->file), diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 0ab3ea7f7525..4b0e15c2b2a8 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1234,7 +1234,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) symbol_conf.priv_size = sizeof(struct annotation); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); - if (symbol__init() < 0) + if (symbol__init(NULL) < 0) return -1; sort__setup_elide(stdout); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8a83bd835327..d080b9cf0354 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1411,7 +1411,7 @@ static int trace__tool_process(struct perf_tool *tool, static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) { - int err = symbol__init(); + int err = symbol__init(NULL); if (err) return err; @@ -2245,7 +2245,7 @@ static int trace__replay(struct trace *trace) if (session == NULL) return -ENOMEM; - if (symbol__init() < 0) + if (symbol__init(&session->header.env) < 0) goto out; trace->host = &session->machines.host; diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 6f8b01bc6033..c6796d22423a 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -297,7 +297,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) symbol_conf.sort_by_name = true; symbol_conf.try_vmlinux_path = true; - if (symbol__init() < 0) + if (symbol__init(NULL) < 0) return -1; if (skip != NULL) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 443225cb62f7..784ea42ad8cb 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -79,7 +79,7 @@ static int init_symbol_maps(bool user_only) int ret; symbol_conf.sort_by_name = true; - ret = symbol__init(); + ret = symbol__init(NULL); if (ret < 0) { pr_debug("Failed to init symbol map.\n"); goto out; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 009a9d064f11..ac098a3c2a31 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -15,6 +15,7 @@ #include "machine.h" #include "symbol.h" #include "strlist.h" +#include "header.h" #include #include @@ -1749,10 +1750,11 @@ static void vmlinux_path__exit(void) zfree(&vmlinux_path); } -static int vmlinux_path__init(void) +static int vmlinux_path__init(struct perf_session_env *env) { struct utsname uts; char bf[PATH_MAX]; + char *kernel_version; vmlinux_path = malloc(sizeof(char *) * 5); if (vmlinux_path == NULL) @@ -1767,25 +1769,31 @@ static int vmlinux_path__init(void) goto out_fail; ++vmlinux_path__nr_entries; - /* only try running kernel version if no symfs was given */ + /* only try kernel version if no symfs was given */ if (symbol_conf.symfs[0] != 0) return 0; - if (uname(&uts) < 0) - goto out_fail; + if (env) { + kernel_version = env->os_release; + } else { + if (uname(&uts) < 0) + goto out_fail; + + kernel_version = uts.release; + } - snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); + snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version); vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); if (vmlinux_path[vmlinux_path__nr_entries] == NULL) goto out_fail; ++vmlinux_path__nr_entries; - snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); + snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version); vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); if (vmlinux_path[vmlinux_path__nr_entries] == NULL) goto out_fail; ++vmlinux_path__nr_entries; snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", - uts.release); + kernel_version); vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); if (vmlinux_path[vmlinux_path__nr_entries] == NULL) goto out_fail; @@ -1831,7 +1839,7 @@ static bool symbol__read_kptr_restrict(void) return value; } -int symbol__init(void) +int symbol__init(struct perf_session_env *env) { const char *symfs; @@ -1846,7 +1854,7 @@ int symbol__init(void) symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - sizeof(struct symbol)); - if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) + if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) return -1; if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 196b29104276..b95e3a36d654 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -262,7 +262,8 @@ int modules__parse(const char *filename, void *arg, int filename__read_debuglink(const char *filename, char *debuglink, size_t size); -int symbol__init(void); +struct perf_session_env; +int symbol__init(struct perf_session_env *env); void symbol__exit(void); void symbol__elf_init(void); struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); -- GitLab From 82162b5ae3d152fd7d887b36213f5b6785fe1294 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 13 Aug 2014 15:02:41 +0900 Subject: [PATCH 0265/5088] perf hists browser: Fix a small callchain display bug The currently when perf TUI report shows callchain, the first level chains have bogus '+' sign even though only the last one has children. Since they are on a single line of the chain, toggling intermediate entries has no effect. Fix it to show '+' sign at the last entry only. Note that non-first level callchain entries don't have this problem. Before: --------------------------------------------------------------------------- Children Self Command Shared Object Symbols - 40.70% 0.00% swapper [kernel.kallsyms] [k] cpuidle_wrap_enter + cpuidle_wrap_enter + cpuidle_enter_tk + cpuidle_idle_call + cpu_idle After: --------------------------------------------------------------------------- Children Self Command Shared Object Symbols - 40.70% 0.00% swapper [kernel.kallsyms] [k] cpuidle_wrap_enter cpuidle_wrap_enter cpuidle_enter_tk cpuidle_idle_call + cpu_idle Signed-off-by: Namhyung Kim Acked-by: Ingo Molnar Cc: Andi Kleen Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Frederic Weisbecker Link: http://lkml.kernel.org/r/1407909761-10822-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 045c1e16ac59..1818d1275d02 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -228,8 +228,10 @@ static void callchain_node__init_have_children(struct callchain_node *node) { struct callchain_list *chain; - list_for_each_entry(chain, &node->val, list) + if (!list_empty(&node->val)) { + chain = list_entry(node->val.prev, struct callchain_list, list); chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root); + } callchain_node__init_have_children_rb_tree(node); } -- GitLab From edd114e213751c3274891f692be66eb65771f278 Mon Sep 17 00:00:00 2001 From: "naota@elisp.net" Date: Thu, 7 Aug 2014 00:04:49 +0900 Subject: [PATCH 0266/5088] perf report: Set proper sort__mode for the branch option When you specify "--branch-stack"("-b" for short) or "--no-branch-stack", "branch_mode" variable is set to 1 or 0 respectively. However, the code is just checking if the variable is -1 or not, ignoring "branch_mode == 1" case. Thus "perf report -b" dose not show its result with the branch sorted mode. This patch fix the problem. Signed-off-by: Naohiro Aota Acked-by: Namhyung Kim Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/87y4v1fylq.fsf@elisp.net Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index b9e0fcac4d71..3da59a87ec7c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -730,7 +730,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) has_br_stack = perf_header__has_feat(&session->header, HEADER_BRANCH_STACK); - if (branch_mode == -1 && has_br_stack) { + if ((branch_mode == -1 && has_br_stack) || branch_mode == 1) { sort__mode = SORT_MODE__BRANCH; symbol_conf.cumulate_callchain = false; } -- GitLab From 701937bd59cc94b6913086feb62f05ae565ff2de Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 17:16:05 +0900 Subject: [PATCH 0267/5088] perf top: Fix -z option behavior The current -z option does almost nothing. It doesn't zero the existing samples so that we can see profiles of exited process after last refresh. It seems it only affects annotation. This patch clears existing entries before processing if -z option is given. For this original decaying logic also moved before processing. Reported-by: Stephane Eranian Tested-by: Stephane Eranian Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1407831366-28892-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 23 +++++++++++++++++------ tools/perf/util/hist.c | 22 ++++++++++++++++++++++ tools/perf/util/hist.h | 1 + 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4b0e15c2b2a8..87a6615a40fa 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -276,11 +276,17 @@ static void perf_top__print_sym_table(struct perf_top *top) return; } + if (top->zero) { + hists__delete_entries(&top->sym_evsel->hists); + } else { + hists__decay_entries(&top->sym_evsel->hists, + top->hide_user_symbols, + top->hide_kernel_symbols); + } + hists__collapse_resort(&top->sym_evsel->hists, NULL); hists__output_resort(&top->sym_evsel->hists); - hists__decay_entries(&top->sym_evsel->hists, - top->hide_user_symbols, - top->hide_kernel_symbols); + hists__output_recalc_col_len(&top->sym_evsel->hists, top->print_entries - printed); putchar('\n'); @@ -542,11 +548,16 @@ static void perf_top__sort_new_samples(void *arg) if (t->evlist->selected != NULL) t->sym_evsel = t->evlist->selected; + if (t->zero) { + hists__delete_entries(&t->sym_evsel->hists); + } else { + hists__decay_entries(&t->sym_evsel->hists, + t->hide_user_symbols, + t->hide_kernel_symbols); + } + hists__collapse_resort(&t->sym_evsel->hists, NULL); hists__output_resort(&t->sym_evsel->hists); - hists__decay_entries(&t->sym_evsel->hists, - t->hide_user_symbols, - t->hide_kernel_symbols); } static void *display_thread_tui(void *arg) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 30df6187ee02..86569fa3651d 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -277,6 +277,28 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) } } +void hists__delete_entries(struct hists *hists) +{ + struct rb_node *next = rb_first(&hists->entries); + struct hist_entry *n; + + while (next) { + n = rb_entry(next, struct hist_entry, rb_node); + next = rb_next(&n->rb_node); + + rb_erase(&n->rb_node, &hists->entries); + + if (sort__need_collapse) + rb_erase(&n->rb_node_in, &hists->entries_collapsed); + + --hists->nr_entries; + if (!n->filtered) + --hists->nr_non_filtered_entries; + + hist_entry__free(n); + } +} + /* * histogram, sorted on item, collects periods */ diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 95405a8fbd95..8c9c70e18cbb 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -152,6 +152,7 @@ void hists__output_resort(struct hists *hists); void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); +void hists__delete_entries(struct hists *hists); void hists__output_recalc_col_len(struct hists *hists, int max_rows); u64 hists__total_period(struct hists *hists); -- GitLab From 42337a222c93cd22864f20ef9b157765ab1086a0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Aug 2014 17:16:06 +0900 Subject: [PATCH 0268/5088] perf top: Handle 'z' key for toggle zeroing samples in TUI The perf top TUI lacks 'z' key support to toggle sample zeroing. Add it. Reported-by: Stephane Eranian Tested-by: Stephane Eranian Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1407831366-28892-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 1818d1275d02..4892480e8298 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -10,6 +10,7 @@ #include "../../util/pstack.h" #include "../../util/sort.h" #include "../../util/util.h" +#include "../../util/top.h" #include "../../arch/common.h" #include "../browser.h" @@ -1532,6 +1533,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, "P Print histograms to perf.hist.N\n" "t Zoom into current Thread\n" "V Verbose (DSO names in callchains, etc)\n" + "z Toggle zeroing of samples\n" "/ Filter symbol by name"; if (browser == NULL) @@ -1632,6 +1634,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, case 'F': symbol_conf.filter_relative ^= 1; continue; + case 'z': + if (!is_report_browser(hbt)) { + struct perf_top *top = hbt->arg; + + top->zero = !top->zero; + } + continue; case K_F1: case 'h': case '?': -- GitLab From e71e79457b79a52827039d9d7f253321bfd342bd Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 31 Jul 2014 14:47:42 +0900 Subject: [PATCH 0269/5088] perf symbols: Don't demangle parameters and such by default Some C++ symbols have very long name and they make column length longer. Most of them are about parameters including templates and we can ignore such info most of time IMHO. This patch passes DMGL_NO_OPTS by default when calling bfd_demangle(). One can still see full symbols with -v/--verbose option. before: JS_CallFunctionValue(JSContext*, JSObject*, JS::Value, unsigned int, JS::Value*, JS::Value*) after: JS_CallFunctionValue Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1406785662-5534-9-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol-elf.c | 7 +++++-- tools/perf/util/symbol.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index d75349979e65..ec5ec1c9d9b5 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -939,8 +939,11 @@ int dso__load_sym(struct dso *dso, struct map *map, * to it... */ if (symbol_conf.demangle) { - demangled = bfd_demangle(NULL, elf_name, - DMGL_PARAMS | DMGL_ANSI); + int demangle_flags = DMGL_NO_OPTS; + if (verbose) + demangle_flags = DMGL_PARAMS | DMGL_ANSI; + + demangled = bfd_demangle(NULL, elf_name, demangle_flags); if (demangled != NULL) elf_name = demangled; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index b95e3a36d654..3f95ea0357e3 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -60,6 +60,7 @@ extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, #endif #ifndef DMGL_PARAMS +#define DMGL_NO_OPTS 0 /* For readability... */ #define DMGL_PARAMS (1 << 0) /* Include function args */ #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ #endif -- GitLab From f247fb8191aa7f10d3f6c987e8ef0853ae789a02 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 Jul 2014 09:00:46 +0300 Subject: [PATCH 0270/5088] perf symbols: Fix missing label symbols Label symbols are missing because elf_sec__is_a() fails to find the section because the section strings do not match the section headers because the sections headers are from the 'runtime' object and the sections strings are from the 'symbol source' object. Fix by getting the section strings from the 'runtime' object so that they match the section headers. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406786474-9306-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol-elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index ec5ec1c9d9b5..9fb5e9e9f161 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -736,7 +736,7 @@ int dso__load_sym(struct dso *dso, struct map *map, if (symstrs == NULL) goto out_elf_end; - sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); + sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx); if (sec_strndx == NULL) goto out_elf_end; -- GitLab From bf8e8f4b832972c76d64ab2e2837a48397144887 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 Jul 2014 09:00:51 +0300 Subject: [PATCH 0271/5088] perf evlist: Add 'system_wide' option Add an option to cause a selected event to be opened always without a pid when configured by perf_evsel__config(). This is needed when using the sched_switch tracepoint to follow object code execution. sched_switch occurs before the task switch and so it cannot record it in a context limited to that task. Note that also means that sched_switch is useless when capturing data per-thread, as is the 'context-switches' software event for the same reason. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406786474-9306-9-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 45 +++++++++++++++++++++++++++++++++------- tools/perf/util/evsel.c | 31 ++++++++++++++++++++++----- tools/perf/util/evsel.h | 1 + 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 3b366c085021..c74d8ecc9c70 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -265,17 +265,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist, return 0; } +static int perf_evlist__nr_threads(struct perf_evlist *evlist, + struct perf_evsel *evsel) +{ + if (evsel->system_wide) + return 1; + else + return thread_map__nr(evlist->threads); +} + void perf_evlist__disable(struct perf_evlist *evlist) { int cpu, thread; struct perf_evsel *pos; int nr_cpus = cpu_map__nr(evlist->cpus); - int nr_threads = thread_map__nr(evlist->threads); + int nr_threads; for (cpu = 0; cpu < nr_cpus; cpu++) { evlist__for_each(evlist, pos) { if (!perf_evsel__is_group_leader(pos) || !pos->fd) continue; + nr_threads = perf_evlist__nr_threads(evlist, pos); for (thread = 0; thread < nr_threads; thread++) ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE, 0); @@ -288,12 +298,13 @@ void perf_evlist__enable(struct perf_evlist *evlist) int cpu, thread; struct perf_evsel *pos; int nr_cpus = cpu_map__nr(evlist->cpus); - int nr_threads = thread_map__nr(evlist->threads); + int nr_threads; for (cpu = 0; cpu < nr_cpus; cpu++) { evlist__for_each(evlist, pos) { if (!perf_evsel__is_group_leader(pos) || !pos->fd) continue; + nr_threads = perf_evlist__nr_threads(evlist, pos); for (thread = 0; thread < nr_threads; thread++) ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE, 0); @@ -305,12 +316,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist, struct perf_evsel *evsel) { int cpu, thread, err; + int nr_cpus = cpu_map__nr(evlist->cpus); + int nr_threads = perf_evlist__nr_threads(evlist, evsel); if (!evsel->fd) return 0; - for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { - for (thread = 0; thread < evlist->threads->nr; thread++) { + for (cpu = 0; cpu < nr_cpus; cpu++) { + for (thread = 0; thread < nr_threads; thread++) { err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_DISABLE, 0); if (err) @@ -324,12 +337,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist, struct perf_evsel *evsel) { int cpu, thread, err; + int nr_cpus = cpu_map__nr(evlist->cpus); + int nr_threads = perf_evlist__nr_threads(evlist, evsel); if (!evsel->fd) return -EINVAL; - for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { - for (thread = 0; thread < evlist->threads->nr; thread++) { + for (cpu = 0; cpu < nr_cpus; cpu++) { + for (thread = 0; thread < nr_threads; thread++) { err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0); if (err) @@ -343,7 +358,16 @@ static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) { int nr_cpus = cpu_map__nr(evlist->cpus); int nr_threads = thread_map__nr(evlist->threads); - int nfds = nr_cpus * nr_threads * evlist->nr_entries; + int nfds = 0; + struct perf_evsel *evsel; + + list_for_each_entry(evsel, &evlist->entries, node) { + if (evsel->system_wide) + nfds += nr_cpus; + else + nfds += nr_cpus * nr_threads; + } + evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); return evlist->pollfd != NULL ? 0 : -ENOMEM; } @@ -636,7 +660,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, struct perf_evsel *evsel; evlist__for_each(evlist, evsel) { - int fd = FD(evsel, cpu, thread); + int fd; + + if (evsel->system_wide && thread) + continue; + + fd = FD(evsel, cpu, thread); if (*output == -1) { *output = fd; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 0c8919decac8..66de9a708163 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -695,6 +695,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) { int cpu, thread; + + if (evsel->system_wide) + nthreads = 1; + evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); if (evsel->fd) { @@ -713,6 +717,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea { int cpu, thread; + if (evsel->system_wide) + nthreads = 1; + for (cpu = 0; cpu < ncpus; cpu++) { for (thread = 0; thread < nthreads; thread++) { int fd = FD(evsel, cpu, thread), @@ -743,6 +750,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads) int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) { + if (evsel->system_wide) + nthreads = 1; + evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); if (evsel->sample_id == NULL) return -ENOMEM; @@ -787,6 +797,9 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) { int cpu, thread; + if (evsel->system_wide) + nthreads = 1; + for (cpu = 0; cpu < ncpus; cpu++) for (thread = 0; thread < nthreads; ++thread) { close(FD(evsel, cpu, thread)); @@ -875,6 +888,9 @@ int __perf_evsel__read(struct perf_evsel *evsel, int cpu, thread; struct perf_counts_values *aggr = &evsel->counts->aggr, count; + if (evsel->system_wide) + nthreads = 1; + aggr->val = aggr->ena = aggr->run = 0; for (cpu = 0; cpu < ncpus; cpu++) { @@ -997,13 +1013,18 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, struct thread_map *threads) { - int cpu, thread; + int cpu, thread, nthreads; unsigned long flags = PERF_FLAG_FD_CLOEXEC; int pid = -1, err; enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; + if (evsel->system_wide) + nthreads = 1; + else + nthreads = threads->nr; + if (evsel->fd == NULL && - perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) + perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0) return -ENOMEM; if (evsel->cgrp) { @@ -1027,10 +1048,10 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, for (cpu = 0; cpu < cpus->nr; cpu++) { - for (thread = 0; thread < threads->nr; thread++) { + for (thread = 0; thread < nthreads; thread++) { int group_fd; - if (!evsel->cgrp) + if (!evsel->cgrp && !evsel->system_wide) pid = threads->map[thread]; group_fd = get_group_fd(evsel, cpu, thread); @@ -1103,7 +1124,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, close(FD(evsel, cpu, thread)); FD(evsel, cpu, thread) = -1; } - thread = threads->nr; + thread = nthreads; } while (--cpu >= 0); return err; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index d7f93ce0ebc1..dbb2a0d20907 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -85,6 +85,7 @@ struct perf_evsel { bool needs_swap; bool no_aux_samples; bool immediate; + bool system_wide; /* parse modifier helper */ int exclude_GH; int nr_members; -- GitLab From 60b0896cc35243f515eda2085f9897e296177e45 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 Jul 2014 09:00:52 +0300 Subject: [PATCH 0272/5088] perf evlist: Add perf_evlist__set_tracking_event() Add a function to change which event is used to track mmap, comm and task events. This is needed with Instruction Tracing because the Instruction Tracing event must come first but cannot be used for tracking because it will be disabled under some circumstances. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406786474-9306-10-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 17 +++++++++++++++++ tools/perf/util/evlist.h | 3 +++ tools/perf/util/evsel.c | 3 ++- tools/perf/util/evsel.h | 1 + tools/perf/util/record.c | 2 +- 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c74d8ecc9c70..9d863db3f4b2 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -122,6 +122,7 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) { list_add_tail(&entry->node, &evlist->entries); entry->idx = evlist->nr_entries; + entry->tracking = !entry->idx; if (!evlist->nr_entries++) perf_evlist__set_id_pos(evlist); @@ -1295,3 +1296,19 @@ void perf_evlist__to_front(struct perf_evlist *evlist, list_splice(&move, &evlist->entries); } + +void perf_evlist__set_tracking_event(struct perf_evlist *evlist, + struct perf_evsel *tracking_evsel) +{ + struct perf_evsel *evsel; + + if (tracking_evsel->tracking) + return; + + evlist__for_each(evlist, evsel) { + if (evsel != tracking_evsel) + evsel->tracking = false; + } + + tracking_evsel->tracking = true; +} diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index f5173cd63693..e0084f90c271 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -262,4 +262,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, #define evlist__for_each_safe(evlist, tmp, evsel) \ __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) +void perf_evlist__set_tracking_event(struct perf_evlist *evlist, + struct perf_evsel *tracking_evsel); + #endif /* __PERF_EVLIST_H */ diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 66de9a708163..01ce14c3575e 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -162,6 +162,7 @@ void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr, int idx) { evsel->idx = idx; + evsel->tracking = !idx; evsel->attr = *attr; evsel->leader = evsel; evsel->unit = ""; @@ -561,7 +562,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) { struct perf_evsel *leader = evsel->leader; struct perf_event_attr *attr = &evsel->attr; - int track = !evsel->idx; /* only the first counter needs these */ + int track = evsel->tracking; bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index dbb2a0d20907..7bc314be6a7b 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -86,6 +86,7 @@ struct perf_evsel { bool no_aux_samples; bool immediate; bool system_wide; + bool tracking; /* parse modifier helper */ int exclude_GH; int nr_members; diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index e778afda0fb9..cf69325b985f 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -115,7 +115,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) evlist__for_each(evlist, evsel) { perf_evsel__config(evsel, opts); - if (!evsel->idx && use_comm_exec) + if (evsel->tracking && use_comm_exec) evsel->attr.comm_exec = 1; } -- GitLab From 5a52f33adf02a3e5eafdc1e597a3fe172e620bec Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 Jul 2014 09:00:57 +0300 Subject: [PATCH 0273/5088] perf session: Add perf_session__peek_event() Add a function to peek at other events in the event stream. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406786474-9306-15-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 55 +++++++++++++++++++++++++++++++++++++++ tools/perf/util/session.h | 5 ++++ 2 files changed, 60 insertions(+) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 7e27f1eb260c..1b383bd93af6 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -897,6 +897,61 @@ static void event_swap(union perf_event *event, bool sample_id_all) swap(event, sample_id_all); } +int perf_session__peek_event(struct perf_session *session, off_t file_offset, + void *buf, size_t buf_sz, + union perf_event **event_ptr, + struct perf_sample *sample) +{ + union perf_event *event; + size_t hdr_sz, rest; + int fd; + + if (session->one_mmap && !session->header.needs_swap) { + event = file_offset - session->one_mmap_offset + + session->one_mmap_addr; + goto out_parse_sample; + } + + if (perf_data_file__is_pipe(session->file)) + return -1; + + fd = perf_data_file__fd(session->file); + hdr_sz = sizeof(struct perf_event_header); + + if (buf_sz < hdr_sz) + return -1; + + if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 || + readn(fd, &buf, hdr_sz) != (ssize_t)hdr_sz) + return -1; + + event = (union perf_event *)buf; + + if (session->header.needs_swap) + perf_event_header__bswap(&event->header); + + if (event->header.size < hdr_sz) + return -1; + + rest = event->header.size - hdr_sz; + + if (readn(fd, &buf, rest) != (ssize_t)rest) + return -1; + + if (session->header.needs_swap) + event_swap(event, perf_evlist__sample_id_all(session->evlist)); + +out_parse_sample: + + if (sample && event->header.type < PERF_RECORD_USER_TYPE_START && + perf_evlist__parse_sample(session->evlist, event, sample)) + return -1; + + *event_ptr = event; + + return 0; +} + static s64 perf_session__process_event(struct perf_session *session, union perf_event *event, struct perf_tool *tool, diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 0630e658f8be..8dd41cad2d59 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -45,6 +45,11 @@ void perf_session__delete(struct perf_session *session); void perf_event_header__bswap(struct perf_event_header *hdr); +int perf_session__peek_event(struct perf_session *session, off_t file_offset, + void *buf, size_t buf_sz, + union perf_event **event_ptr, + struct perf_sample *sample); + int __perf_session__process_events(struct perf_session *session, u64 data_offset, u64 data_size, u64 size, struct perf_tool *tool); -- GitLab From 98526ee7229be8537373aebe037b74cac112d84b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 Jul 2014 09:00:59 +0300 Subject: [PATCH 0274/5088] perf script: Allow callchains if any event samples them perf script was not displaying callchains if any selected event did not have PERF_SAMPLE_CALLCHAIN. Change this to disable callchains only if all selected events do not have PERF_SAMPLE_CALLCHAIN. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406786474-9306-17-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 37d2b608d388..c1b7029884b1 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", PERF_OUTPUT_IP)) return -EINVAL; - - if (!no_callchain && - !(attr->sample_type & PERF_SAMPLE_CALLCHAIN)) - symbol_conf.use_callchain = false; } if (PRINT_FIELD(ADDR) && @@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session) set_print_ip_opts(&evsel->attr); } + if (!no_callchain) { + bool use_callchain = false; + + evlist__for_each(session->evlist, evsel) { + if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { + use_callchain = true; + break; + } + } + if (!use_callchain) + symbol_conf.use_callchain = false; + } + /* * set default for tracepoints to print symbols only * if callchains are present -- GitLab From a5563edfa1bd25d052d81f5ad7fe74ba71c3d44e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 Jul 2014 09:01:01 +0300 Subject: [PATCH 0275/5088] perf script python: Add helpers for calling Python objects The Python script API repeatedly uses the same lines of code to get and call objects. Make that into helper functions instead. A side-effect is that some reference counting bugs disappear because the new call_object() function always decrements the reference count of 'retval'. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406786474-9306-19-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../scripting-engines/trace-event-python.c | 114 ++++++++---------- 1 file changed, 47 insertions(+), 67 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index cbce2545da45..26e5f14239ed 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -73,6 +73,35 @@ static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObj Py_DECREF(val); } +static PyObject *get_handler(const char *handler_name) +{ + PyObject *handler; + + handler = PyDict_GetItemString(main_dict, handler_name); + if (handler && !PyCallable_Check(handler)) + return NULL; + return handler; +} + +static void call_object(PyObject *handler, PyObject *args, const char *die_msg) +{ + PyObject *retval; + + retval = PyObject_CallObject(handler, args); + if (retval == NULL) + handler_call_die(die_msg); + Py_DECREF(retval); +} + +static void try_call_object(const char *handler_name, PyObject *args) +{ + PyObject *handler; + + handler = get_handler(handler_name); + if (handler) + call_object(handler, args, handler_name); +} + static void define_value(enum print_arg_type field_type, const char *ev_name, const char *field_name, @@ -80,7 +109,7 @@ static void define_value(enum print_arg_type field_type, const char *field_str) { const char *handler_name = "define_flag_value"; - PyObject *handler, *t, *retval; + PyObject *t; unsigned long long value; unsigned n = 0; @@ -98,13 +127,7 @@ static void define_value(enum print_arg_type field_type, PyTuple_SetItem(t, n++, PyInt_FromLong(value)); PyTuple_SetItem(t, n++, PyString_FromString(field_str)); - handler = PyDict_GetItemString(main_dict, handler_name); - if (handler && PyCallable_Check(handler)) { - retval = PyObject_CallObject(handler, t); - if (retval == NULL) - handler_call_die(handler_name); - Py_DECREF(retval); - } + try_call_object(handler_name, t); Py_DECREF(t); } @@ -127,7 +150,7 @@ static void define_field(enum print_arg_type field_type, const char *delim) { const char *handler_name = "define_flag_field"; - PyObject *handler, *t, *retval; + PyObject *t; unsigned n = 0; if (field_type == PRINT_SYMBOL) @@ -145,13 +168,7 @@ static void define_field(enum print_arg_type field_type, if (field_type == PRINT_FLAGS) PyTuple_SetItem(t, n++, PyString_FromString(delim)); - handler = PyDict_GetItemString(main_dict, handler_name); - if (handler && PyCallable_Check(handler)) { - retval = PyObject_CallObject(handler, t); - if (retval == NULL) - handler_call_die(handler_name); - Py_DECREF(retval); - } + try_call_object(handler_name, t); Py_DECREF(t); } @@ -362,7 +379,7 @@ static void python_process_tracepoint(struct perf_sample *sample, struct thread *thread, struct addr_location *al) { - PyObject *handler, *retval, *context, *t, *obj, *callchain; + PyObject *handler, *context, *t, *obj, *callchain; PyObject *dict = NULL; static char handler_name[256]; struct format_field *field; @@ -387,9 +404,7 @@ static void python_process_tracepoint(struct perf_sample *sample, sprintf(handler_name, "%s__%s", event->system, event->name); - handler = PyDict_GetItemString(main_dict, handler_name); - if (handler && !PyCallable_Check(handler)) - handler = NULL; + handler = get_handler(handler_name); if (!handler) { dict = PyDict_New(); if (!dict) @@ -450,19 +465,9 @@ static void python_process_tracepoint(struct perf_sample *sample, Py_FatalError("error resizing Python tuple"); if (handler) { - retval = PyObject_CallObject(handler, t); - if (retval == NULL) - handler_call_die(handler_name); - Py_DECREF(retval); + call_object(handler, t, handler_name); } else { - handler = PyDict_GetItemString(main_dict, "trace_unhandled"); - if (handler && PyCallable_Check(handler)) { - - retval = PyObject_CallObject(handler, t); - if (retval == NULL) - handler_call_die("trace_unhandled"); - Py_DECREF(retval); - } + try_call_object("trace_unhandled", t); Py_DECREF(dict); } @@ -474,7 +479,7 @@ static void python_process_general_event(struct perf_sample *sample, struct thread *thread, struct addr_location *al) { - PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample; + PyObject *handler, *t, *dict, *callchain, *dict_sample; static char handler_name[64]; unsigned n = 0; @@ -496,8 +501,8 @@ static void python_process_general_event(struct perf_sample *sample, snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); - handler = PyDict_GetItemString(main_dict, handler_name); - if (!handler || !PyCallable_Check(handler)) + handler = get_handler(handler_name); + if (!handler) goto exit; pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); @@ -539,10 +544,7 @@ static void python_process_general_event(struct perf_sample *sample, if (_PyTuple_Resize(&t, n) == -1) Py_FatalError("error resizing Python tuple"); - retval = PyObject_CallObject(handler, t); - if (retval == NULL) - handler_call_die(handler_name); - Py_DECREF(retval); + call_object(handler, t, handler_name); exit: Py_DECREF(dict); Py_DECREF(t); @@ -566,36 +568,24 @@ static void python_process_event(union perf_event *event __maybe_unused, static int run_start_sub(void) { - PyObject *handler, *retval; - int err = 0; - main_module = PyImport_AddModule("__main__"); if (main_module == NULL) return -1; Py_INCREF(main_module); main_dict = PyModule_GetDict(main_module); - if (main_dict == NULL) { - err = -1; + if (main_dict == NULL) goto error; - } Py_INCREF(main_dict); - handler = PyDict_GetItemString(main_dict, "trace_begin"); - if (handler == NULL || !PyCallable_Check(handler)) - goto out; + try_call_object("trace_begin", NULL); - retval = PyObject_CallObject(handler, NULL); - if (retval == NULL) - handler_call_die("trace_begin"); + return 0; - Py_DECREF(retval); - return err; error: Py_XDECREF(main_dict); Py_XDECREF(main_module); -out: - return err; + return -1; } /* @@ -654,23 +644,13 @@ static int python_start_script(const char *script, int argc, const char **argv) */ static int python_stop_script(void) { - PyObject *handler, *retval; - int err = 0; + try_call_object("trace_end", NULL); - handler = PyDict_GetItemString(main_dict, "trace_end"); - if (handler == NULL || !PyCallable_Check(handler)) - goto out; - - retval = PyObject_CallObject(handler, NULL); - if (retval == NULL) - handler_call_die("trace_end"); - Py_DECREF(retval); -out: Py_XDECREF(main_dict); Py_XDECREF(main_module); Py_Finalize(); - return err; + return 0; } static int python_generate_script(struct pevent *pevent, const char *outfile) -- GitLab From 65de51f93ebf9305ec011da59c0b5fe29429d1b9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 Jul 2014 09:00:44 +0300 Subject: [PATCH 0276/5088] perf tools: Identify which comms are from exec For grouping together all the data from a single execution, which is needed for pairing calls and returns e.g. any outstanding calls when a process exec's will never return. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406786474-9306-2-git-send-email-adrian.hunter@intel.com [ Remove testing if comm->exec is false before setting it to true ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/comm.c | 7 +++++-- tools/perf/util/comm.h | 6 ++++-- tools/perf/util/machine.c | 4 +++- tools/perf/util/thread.c | 24 +++++++++++++++++++----- tools/perf/util/thread.h | 10 +++++++++- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c index f9e777629e21..b2bb59df65e1 100644 --- a/tools/perf/util/comm.c +++ b/tools/perf/util/comm.c @@ -74,7 +74,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root) return new; } -struct comm *comm__new(const char *str, u64 timestamp) +struct comm *comm__new(const char *str, u64 timestamp, bool exec) { struct comm *comm = zalloc(sizeof(*comm)); @@ -82,6 +82,7 @@ struct comm *comm__new(const char *str, u64 timestamp) return NULL; comm->start = timestamp; + comm->exec = exec; comm->comm_str = comm_str__findnew(str, &comm_str_root); if (!comm->comm_str) { @@ -94,7 +95,7 @@ struct comm *comm__new(const char *str, u64 timestamp) return comm; } -int comm__override(struct comm *comm, const char *str, u64 timestamp) +int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec) { struct comm_str *new, *old = comm->comm_str; @@ -106,6 +107,8 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp) comm_str__put(old); comm->comm_str = new; comm->start = timestamp; + if (exec) + comm->exec = true; return 0; } diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h index fac5bd51befc..51c10ab257f8 100644 --- a/tools/perf/util/comm.h +++ b/tools/perf/util/comm.h @@ -11,11 +11,13 @@ struct comm { struct comm_str *comm_str; u64 start; struct list_head list; + bool exec; }; void comm__free(struct comm *comm); -struct comm *comm__new(const char *str, u64 timestamp); +struct comm *comm__new(const char *str, u64 timestamp, bool exec); const char *comm__str(const struct comm *comm); -int comm__override(struct comm *comm, const char *str, u64 timestamp); +int comm__override(struct comm *comm, const char *str, u64 timestamp, + bool exec); #endif /* __PERF_COMM_H */ diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 16bba9fff2c8..ea3e09f6a9c6 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -404,11 +404,13 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event struct thread *thread = machine__findnew_thread(machine, event->comm.pid, event->comm.tid); + bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC; if (dump_trace) perf_event__fprintf_comm(event, stdout); - if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) { + if (thread == NULL || + __thread__set_comm(thread, event->comm.comm, sample->time, exec)) { dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); return -1; } diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 12c7a253a63c..a9df7f2c6dc9 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -42,7 +42,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) goto err_thread; snprintf(comm_str, 32, ":%d", tid); - comm = comm__new(comm_str, 0); + comm = comm__new(comm_str, 0, false); free(comm_str); if (!comm) goto err_thread; @@ -81,19 +81,33 @@ struct comm *thread__comm(const struct thread *thread) return list_first_entry(&thread->comm_list, struct comm, list); } +struct comm *thread__exec_comm(const struct thread *thread) +{ + struct comm *comm, *last = NULL; + + list_for_each_entry(comm, &thread->comm_list, list) { + if (comm->exec) + return comm; + last = comm; + } + + return last; +} + /* CHECKME: time should always be 0 if event aren't ordered */ -int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) +int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp, + bool exec) { struct comm *new, *curr = thread__comm(thread); int err; /* Override latest entry if it had no specific time coverage */ - if (!curr->start) { - err = comm__override(curr, str, timestamp); + if (!curr->start && !curr->exec) { + err = comm__override(curr, str, timestamp, exec); if (err) return err; } else { - new = comm__new(str, timestamp); + new = comm__new(str, timestamp, exec); if (!new) return -ENOMEM; list_add(&new->list, &thread->comm_list); diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 716b7723cce2..8c75fa774706 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread) thread->dead = true; } -int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp); +int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp, + bool exec); +static inline int thread__set_comm(struct thread *thread, const char *comm, + u64 timestamp) +{ + return __thread__set_comm(thread, comm, timestamp, false); +} + int thread__comm_len(struct thread *thread); struct comm *thread__comm(const struct thread *thread); +struct comm *thread__exec_comm(const struct thread *thread); const char *thread__comm_str(const struct thread *thread); void thread__insert_map(struct thread *thread, struct map *map); int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); -- GitLab From cfe1c41405fe9a559f8b3c24c904b2bb42d4a6e8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 Jul 2014 09:00:45 +0300 Subject: [PATCH 0277/5088] perf machine: Add machine__thread_exec_comm() Add machine__thread_exec_comm() to return the comm that matches the last exec, if the comm_exec flag is present, or the last comm otherwise. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406786474-9306-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 26 ++++++++++++++++++++++++++ tools/perf/util/machine.h | 4 ++++ tools/perf/util/session.c | 24 +++++++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index ea3e09f6a9c6..b093b93607fb 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -31,6 +31,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->symbol_filter = NULL; machine->id_hdr_size = 0; + machine->comm_exec = false; machine->root_dir = strdup(root_dir); if (machine->root_dir == NULL) @@ -179,6 +180,19 @@ void machines__set_symbol_filter(struct machines *machines, } } +void machines__set_comm_exec(struct machines *machines, bool comm_exec) +{ + struct rb_node *nd; + + machines->host.comm_exec = comm_exec; + + for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { + struct machine *machine = rb_entry(nd, struct machine, rb_node); + + machine->comm_exec = comm_exec; + } +} + struct machine *machines__find(struct machines *machines, pid_t pid) { struct rb_node **p = &machines->guests.rb_node; @@ -398,6 +412,15 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid, return __machine__findnew_thread(machine, pid, tid, false); } +struct comm *machine__thread_exec_comm(struct machine *machine, + struct thread *thread) +{ + if (machine->comm_exec) + return thread__exec_comm(thread); + else + return thread__comm(thread); +} + int machine__process_comm_event(struct machine *machine, union perf_event *event, struct perf_sample *sample) { @@ -406,6 +429,9 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event event->comm.tid); bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC; + if (exec) + machine->comm_exec = true; + if (dump_trace) perf_event__fprintf_comm(event, stdout); diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index b972824e6294..61216e028319 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -26,6 +26,7 @@ struct machine { struct rb_node rb_node; pid_t pid; u16 id_hdr_size; + bool comm_exec; char *root_dir; struct rb_root threads; struct list_head dead_threads; @@ -47,6 +48,8 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type) struct thread *machine__find_thread(struct machine *machine, pid_t pid, pid_t tid); +struct comm *machine__thread_exec_comm(struct machine *machine, + struct thread *thread); int machine__process_comm_event(struct machine *machine, union perf_event *event, struct perf_sample *sample); @@ -88,6 +91,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size); void machines__set_symbol_filter(struct machines *machines, symbol_filter_t symbol_filter); +void machines__set_comm_exec(struct machines *machines, bool comm_exec); struct machine *machine__new_host(void); int machine__init(struct machine *machine, const char *root_dir, pid_t pid); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 1b383bd93af6..6d2d50dea1d8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -67,6 +67,25 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session) machines__destroy_kernel_maps(&session->machines); } +static bool perf_session__has_comm_exec(struct perf_session *session) +{ + struct perf_evsel *evsel; + + evlist__for_each(session->evlist, evsel) { + if (evsel->attr.comm_exec) + return true; + } + + return false; +} + +static void perf_session__set_comm_exec(struct perf_session *session) +{ + bool comm_exec = perf_session__has_comm_exec(session); + + machines__set_comm_exec(&session->machines, comm_exec); +} + struct perf_session *perf_session__new(struct perf_data_file *file, bool repipe, struct perf_tool *tool) { @@ -90,6 +109,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file, goto out_close; perf_session__set_id_hdr_size(session); + perf_session__set_comm_exec(session); } } @@ -866,8 +886,10 @@ static s64 perf_session__process_user_event(struct perf_session *session, switch (event->header.type) { case PERF_RECORD_HEADER_ATTR: err = tool->attr(tool, event, &session->evlist); - if (err == 0) + if (err == 0) { perf_session__set_id_hdr_size(session); + perf_session__set_comm_exec(session); + } return err; case PERF_RECORD_HEADER_EVENT_TYPE: /* -- GitLab From bf4939027decde7aaaf8b5dbeee70126d2822eb6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 Jul 2014 09:01:04 +0300 Subject: [PATCH 0278/5088] perf tools: Add flags and insn_len to struct sample The flags will be used to export branch type and transaction status. insn_len is preparation for pairing calls and returns because the return address equals the call address plus the instruction length (insn_len). Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406786474-9306-22-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 94d6976180da..7eb7107731ec 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -156,6 +156,8 @@ struct perf_sample { u32 cpu; u32 raw_size; u64 data_src; + u32 flags; + u16 insn_len; void *raw_data; struct ip_callchain *callchain; struct branch_stack *branch_stack; -- GitLab From 1c65056c547141a0cb52fb8e6056f63524d2bbf2 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 Jul 2014 09:00:56 +0300 Subject: [PATCH 0279/5088] perf evlist: Add perf_evlist__enable_event_idx() Add a function to enable a specific event within a specific perf event buffer. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1406786474-9306-14-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 47 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evlist.h | 2 ++ 2 files changed, 49 insertions(+) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 9d863db3f4b2..5dcd28c79c6e 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -355,6 +355,53 @@ int perf_evlist__enable_event(struct perf_evlist *evlist, return 0; } +static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, + struct perf_evsel *evsel, int cpu) +{ + int thread, err; + int nr_threads = perf_evlist__nr_threads(evlist, evsel); + + if (!evsel->fd) + return -EINVAL; + + for (thread = 0; thread < nr_threads; thread++) { + err = ioctl(FD(evsel, cpu, thread), + PERF_EVENT_IOC_ENABLE, 0); + if (err) + return err; + } + return 0; +} + +static int perf_evlist__enable_event_thread(struct perf_evlist *evlist, + struct perf_evsel *evsel, + int thread) +{ + int cpu, err; + int nr_cpus = cpu_map__nr(evlist->cpus); + + if (!evsel->fd) + return -EINVAL; + + for (cpu = 0; cpu < nr_cpus; cpu++) { + err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0); + if (err) + return err; + } + return 0; +} + +int perf_evlist__enable_event_idx(struct perf_evlist *evlist, + struct perf_evsel *evsel, int idx) +{ + bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus); + + if (per_cpu_mmaps) + return perf_evlist__enable_event_cpu(evlist, evsel, idx); + else + return perf_evlist__enable_event_thread(evlist, evsel, idx); +} + static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) { int nr_cpus = cpu_map__nr(evlist->cpus); diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index e0084f90c271..106de53a6a74 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -122,6 +122,8 @@ int perf_evlist__disable_event(struct perf_evlist *evlist, struct perf_evsel *evsel); int perf_evlist__enable_event(struct perf_evlist *evlist, struct perf_evsel *evsel); +int perf_evlist__enable_event_idx(struct perf_evlist *evlist, + struct perf_evsel *evsel, int idx); void perf_evlist__set_selected(struct perf_evlist *evlist, struct perf_evsel *evsel); -- GitLab From f6b4ecee0eb7bfa66ae8d5652105ed4da53209a3 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 17:02:18 +0200 Subject: [PATCH 0280/5088] locking,x86: Kill atomic_or_long() There are no users, kill it. Signed-off-by: Peter Zijlstra Cc: Jesse Brandeburg Cc: Linus Torvalds Cc: Paul E. McKenney Link: http://lkml.kernel.org/r/20140508135851.768177189@infradead.org Signed-off-by: Ingo Molnar --- arch/x86/include/asm/atomic.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index 6dd1c7dd0473..bf20c817ed34 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -219,21 +219,6 @@ static inline short int atomic_inc_short(short int *v) return *v; } -#ifdef CONFIG_X86_64 -/** - * atomic_or_long - OR of two long integers - * @v1: pointer to type unsigned long - * @v2: pointer to type unsigned long - * - * Atomically ORs @v1 and @v2 - * Returns the result of the OR - */ -static inline void atomic_or_long(unsigned long *v1, unsigned long v2) -{ - asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2)); -} -#endif - /* These are x86-specific, used by some header files */ #define atomic_clear_mask(mask, addr) \ asm volatile(LOCK_PREFIX "andl %0,%1" \ -- GitLab From b93c7b8c5b281bf3646d6c5b6e05249b98cc5ab7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 23 Mar 2014 16:25:53 +0100 Subject: [PATCH 0281/5088] locking,arch,alpha: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Cc: Matt Turner Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Linus Torvalds Signed-off-by: Peter Zijlstra Cc: Ivan Kokshaysky Cc: Linus Torvalds Cc: Matt Turner Cc: Paul E. McKenney Cc: Richard Henderson Cc: linux-alpha@vger.kernel.org Link: http://lkml.kernel.org/r/20140508135851.832107183@infradead.org Signed-off-by: Ingo Molnar --- arch/alpha/include/asm/atomic.h | 213 ++++++++++++-------------------- 1 file changed, 80 insertions(+), 133 deletions(-) diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index ed60a1ee1ed3..6fbb53a13049 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -29,145 +29,92 @@ * branch back to restart the operation. */ -static __inline__ void atomic_add(int i, atomic_t * v) -{ - unsigned long temp; - __asm__ __volatile__( - "1: ldl_l %0,%1\n" - " addl %0,%2,%0\n" - " stl_c %0,%1\n" - " beq %0,2f\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (v->counter) - :"Ir" (i), "m" (v->counter)); -} - -static __inline__ void atomic64_add(long i, atomic64_t * v) -{ - unsigned long temp; - __asm__ __volatile__( - "1: ldq_l %0,%1\n" - " addq %0,%2,%0\n" - " stq_c %0,%1\n" - " beq %0,2f\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (v->counter) - :"Ir" (i), "m" (v->counter)); -} - -static __inline__ void atomic_sub(int i, atomic_t * v) -{ - unsigned long temp; - __asm__ __volatile__( - "1: ldl_l %0,%1\n" - " subl %0,%2,%0\n" - " stl_c %0,%1\n" - " beq %0,2f\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (v->counter) - :"Ir" (i), "m" (v->counter)); +#define ATOMIC_OP(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" \ + " stl_c %0,%1\n" \ + " beq %0,2f\n" \ + ".subsection 2\n" \ + "2: br 1b\n" \ + ".previous" \ + :"=&r" (temp), "=m" (v->counter) \ + :"Ir" (i), "m" (v->counter)); \ +} \ + +#define ATOMIC_OP_RETURN(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" \ + " stl_c %0,%1\n" \ + " beq %0,2f\n" \ + ".subsection 2\n" \ + "2: br 1b\n" \ + ".previous" \ + :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ + :"Ir" (i), "m" (v->counter) : "memory"); \ + smp_mb(); \ + return result; \ } -static __inline__ void atomic64_sub(long i, atomic64_t * v) -{ - unsigned long temp; - __asm__ __volatile__( - "1: ldq_l %0,%1\n" - " subq %0,%2,%0\n" - " stq_c %0,%1\n" - " beq %0,2f\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (v->counter) - :"Ir" (i), "m" (v->counter)); -} - - -/* - * Same as above, but return the result value - */ -static inline int atomic_add_return(int i, atomic_t *v) -{ - long temp, result; - smp_mb(); - __asm__ __volatile__( - "1: ldl_l %0,%1\n" - " addl %0,%3,%2\n" - " addl %0,%3,%0\n" - " stl_c %0,%1\n" - " beq %0,2f\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (v->counter), "=&r" (result) - :"Ir" (i), "m" (v->counter) : "memory"); - smp_mb(); - return result; +#define ATOMIC64_OP(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" \ + " stq_c %0,%1\n" \ + " beq %0,2f\n" \ + ".subsection 2\n" \ + "2: br 1b\n" \ + ".previous" \ + :"=&r" (temp), "=m" (v->counter) \ + :"Ir" (i), "m" (v->counter)); \ +} \ + +#define ATOMIC64_OP_RETURN(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" \ + " stq_c %0,%1\n" \ + " beq %0,2f\n" \ + ".subsection 2\n" \ + "2: br 1b\n" \ + ".previous" \ + :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ + :"Ir" (i), "m" (v->counter) : "memory"); \ + smp_mb(); \ + return result; \ } -static __inline__ long atomic64_add_return(long i, atomic64_t * v) -{ - long temp, result; - smp_mb(); - __asm__ __volatile__( - "1: ldq_l %0,%1\n" - " addq %0,%3,%2\n" - " addq %0,%3,%0\n" - " stq_c %0,%1\n" - " beq %0,2f\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (v->counter), "=&r" (result) - :"Ir" (i), "m" (v->counter) : "memory"); - smp_mb(); - return result; -} +#define ATOMIC_OPS(opg) \ + ATOMIC_OP(opg) \ + ATOMIC_OP_RETURN(opg) \ + ATOMIC64_OP(opg) \ + ATOMIC64_OP_RETURN(opg) -static __inline__ long atomic_sub_return(int i, atomic_t * v) -{ - long temp, result; - smp_mb(); - __asm__ __volatile__( - "1: ldl_l %0,%1\n" - " subl %0,%3,%2\n" - " subl %0,%3,%0\n" - " stl_c %0,%1\n" - " beq %0,2f\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (v->counter), "=&r" (result) - :"Ir" (i), "m" (v->counter) : "memory"); - smp_mb(); - return result; -} +ATOMIC_OPS(add) +ATOMIC_OPS(sub) -static __inline__ long atomic64_sub_return(long i, atomic64_t * v) -{ - long temp, result; - smp_mb(); - __asm__ __volatile__( - "1: ldq_l %0,%1\n" - " subq %0,%3,%2\n" - " subq %0,%3,%0\n" - " stq_c %0,%1\n" - " beq %0,2f\n" - ".subsection 2\n" - "2: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (v->counter), "=&r" (result) - :"Ir" (i), "m" (v->counter) : "memory"); - smp_mb(); - return result; -} +#undef ATOMIC_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP #define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) -- GitLab From f7d11e93ee97a37da1947b7c4e1794705a6f360c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 23 Mar 2014 16:29:31 +0100 Subject: [PATCH 0282/5088] locking,arch,arc: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Vineet Gupta Link: http://lkml.kernel.org/r/20140508135851.886055622@infradead.org Signed-off-by: Ingo Molnar --- arch/arc/include/asm/atomic.h | 184 ++++++++++++---------------------- 1 file changed, 63 insertions(+), 121 deletions(-) diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 83f03ca6caf6..173f303a868f 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -25,79 +25,36 @@ #define atomic_set(v, i) (((v)->counter) = (i)) -static inline void atomic_add(int i, atomic_t *v) -{ - unsigned int temp; - - __asm__ __volatile__( - "1: llock %0, [%1] \n" - " add %0, %0, %2 \n" - " scond %0, [%1] \n" - " bnz 1b \n" - : "=&r"(temp) /* Early clobber, to prevent reg reuse */ - : "r"(&v->counter), "ir"(i) - : "cc"); -} - -static inline void atomic_sub(int i, atomic_t *v) -{ - unsigned int temp; - - __asm__ __volatile__( - "1: llock %0, [%1] \n" - " sub %0, %0, %2 \n" - " scond %0, [%1] \n" - " bnz 1b \n" - : "=&r"(temp) - : "r"(&v->counter), "ir"(i) - : "cc"); -} - -/* add and also return the new value */ -static inline int atomic_add_return(int i, atomic_t *v) -{ - unsigned int temp; - - __asm__ __volatile__( - "1: llock %0, [%1] \n" - " add %0, %0, %2 \n" - " scond %0, [%1] \n" - " bnz 1b \n" - : "=&r"(temp) - : "r"(&v->counter), "ir"(i) - : "cc"); - - return temp; -} - -static inline int atomic_sub_return(int i, atomic_t *v) -{ - unsigned int temp; - - __asm__ __volatile__( - "1: llock %0, [%1] \n" - " sub %0, %0, %2 \n" - " scond %0, [%1] \n" - " bnz 1b \n" - : "=&r"(temp) - : "r"(&v->counter), "ir"(i) - : "cc"); - - return temp; -} - -static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) -{ - unsigned int temp; - - __asm__ __volatile__( - "1: llock %0, [%1] \n" - " bic %0, %0, %2 \n" - " scond %0, [%1] \n" - " bnz 1b \n" - : "=&r"(temp) - : "r"(addr), "ir"(mask) - : "cc"); +#define ATOMIC_OP(op, c_op, asm_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned int temp; \ + \ + __asm__ __volatile__( \ + "1: llock %0, [%1] \n" \ + " " #asm_op " %0, %0, %2 \n" \ + " scond %0, [%1] \n" \ + " bnz 1b \n" \ + : "=&r"(temp) /* Early clobber, to prevent reg reuse */ \ + : "r"(&v->counter), "ir"(i) \ + : "cc"); \ +} \ + +#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned int temp; \ + \ + __asm__ __volatile__( \ + "1: llock %0, [%1] \n" \ + " " #asm_op " %0, %0, %2 \n" \ + " scond %0, [%1] \n" \ + " bnz 1b \n" \ + : "=&r"(temp) \ + : "r"(&v->counter), "ir"(i) \ + : "cc"); \ + \ + return temp; \ } #else /* !CONFIG_ARC_HAS_LLSC */ @@ -126,6 +83,7 @@ static inline void atomic_set(atomic_t *v, int i) v->counter = i; atomic_ops_unlock(flags); } + #endif /* @@ -133,62 +91,46 @@ static inline void atomic_set(atomic_t *v, int i) * Locking would change to irq-disabling only (UP) and spinlocks (SMP) */ -static inline void atomic_add(int i, atomic_t *v) -{ - unsigned long flags; - - atomic_ops_lock(flags); - v->counter += i; - atomic_ops_unlock(flags); +#define ATOMIC_OP(op, c_op, asm_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + \ + atomic_ops_lock(flags); \ + v->counter c_op i; \ + atomic_ops_unlock(flags); \ } -static inline void atomic_sub(int i, atomic_t *v) -{ - unsigned long flags; - - atomic_ops_lock(flags); - v->counter -= i; - atomic_ops_unlock(flags); +#define ATOMIC_OP_RETURN(op, c_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + unsigned long temp; \ + \ + atomic_ops_lock(flags); \ + temp = v->counter; \ + temp c_op i; \ + v->counter = temp; \ + atomic_ops_unlock(flags); \ + \ + return temp; \ } -static inline int atomic_add_return(int i, atomic_t *v) -{ - unsigned long flags; - unsigned long temp; - - atomic_ops_lock(flags); - temp = v->counter; - temp += i; - v->counter = temp; - atomic_ops_unlock(flags); - - return temp; -} - -static inline int atomic_sub_return(int i, atomic_t *v) -{ - unsigned long flags; - unsigned long temp; - - atomic_ops_lock(flags); - temp = v->counter; - temp -= i; - v->counter = temp; - atomic_ops_unlock(flags); +#endif /* !CONFIG_ARC_HAS_LLSC */ - return temp; -} +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ + ATOMIC_OP_RETURN(op, c_op, asm_op) -static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) -{ - unsigned long flags; +ATOMIC_OPS(add, +=, add) +ATOMIC_OPS(sub, -=, sub) +ATOMIC_OP(and, &=, and) - atomic_ops_lock(flags); - *addr &= ~mask; - atomic_ops_unlock(flags); -} +#define atomic_clear_mask(mask, v) atomic_and(~(mask), (v)) -#endif /* !CONFIG_ARC_HAS_LLSC */ +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP /** * __atomic_add_unless - add unless the number is a given value -- GitLab From aee9a55452f0371258e18b41649ce650ff344090 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 23 Mar 2014 16:38:18 +0100 Subject: [PATCH 0283/5088] locking,arch,arm: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Requires the asm_op because of eor. Signed-off-by: Peter Zijlstra Acked-by: Will Deacon Cc: Chen Gang Cc: Linus Torvalds Cc: Nicolas Pitre Cc: Paul E. McKenney Cc: Russell King Cc: Albin Tonnerre Cc: Victor Kamensky Cc: Catalin Marinas Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/20140508135851.939725247@infradead.org Signed-off-by: Ingo Molnar --- arch/arm/include/asm/atomic.h | 305 ++++++++++++++-------------------- 1 file changed, 123 insertions(+), 182 deletions(-) diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 3040359094d9..832f1cdfcd6a 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -37,84 +37,47 @@ * store exclusive to ensure that these are atomic. We may loop * to ensure that the update happens. */ -static inline void atomic_add(int i, atomic_t *v) -{ - unsigned long tmp; - int result; - - prefetchw(&v->counter); - __asm__ __volatile__("@ atomic_add\n" -"1: ldrex %0, [%3]\n" -" add %0, %0, %4\n" -" strex %1, %0, [%3]\n" -" teq %1, #0\n" -" bne 1b" - : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) - : "r" (&v->counter), "Ir" (i) - : "cc"); -} -static inline int atomic_add_return(int i, atomic_t *v) -{ - unsigned long tmp; - int result; - - smp_mb(); - prefetchw(&v->counter); - - __asm__ __volatile__("@ atomic_add_return\n" -"1: ldrex %0, [%3]\n" -" add %0, %0, %4\n" -" strex %1, %0, [%3]\n" -" teq %1, #0\n" -" bne 1b" - : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) - : "r" (&v->counter), "Ir" (i) - : "cc"); - - smp_mb(); - - return result; -} - -static inline void atomic_sub(int i, atomic_t *v) -{ - unsigned long tmp; - int result; - - prefetchw(&v->counter); - __asm__ __volatile__("@ atomic_sub\n" -"1: ldrex %0, [%3]\n" -" sub %0, %0, %4\n" -" strex %1, %0, [%3]\n" -" teq %1, #0\n" -" bne 1b" - : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) - : "r" (&v->counter), "Ir" (i) - : "cc"); -} - -static inline int atomic_sub_return(int i, atomic_t *v) -{ - unsigned long tmp; - int result; - - smp_mb(); - prefetchw(&v->counter); - - __asm__ __volatile__("@ atomic_sub_return\n" -"1: ldrex %0, [%3]\n" -" sub %0, %0, %4\n" -" strex %1, %0, [%3]\n" -" teq %1, #0\n" -" bne 1b" - : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) - : "r" (&v->counter), "Ir" (i) - : "cc"); - - smp_mb(); - - return result; +#define ATOMIC_OP(op, c_op, asm_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long tmp; \ + int result; \ + \ + prefetchw(&v->counter); \ + __asm__ __volatile__("@ atomic_" #op "\n" \ +"1: ldrex %0, [%3]\n" \ +" " #asm_op " %0, %0, %4\n" \ +" strex %1, %0, [%3]\n" \ +" teq %1, #0\n" \ +" bne 1b" \ + : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ + : "r" (&v->counter), "Ir" (i) \ + : "cc"); \ +} \ + +#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long tmp; \ + int result; \ + \ + smp_mb(); \ + prefetchw(&v->counter); \ + \ + __asm__ __volatile__("@ atomic_" #op "_return\n" \ +"1: ldrex %0, [%3]\n" \ +" " #asm_op " %0, %0, %4\n" \ +" strex %1, %0, [%3]\n" \ +" teq %1, #0\n" \ +" bne 1b" \ + : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ + : "r" (&v->counter), "Ir" (i) \ + : "cc"); \ + \ + smp_mb(); \ + \ + return result; \ } static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) @@ -174,33 +137,29 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #error SMP not supported on pre-ARMv6 CPUs #endif -static inline int atomic_add_return(int i, atomic_t *v) -{ - unsigned long flags; - int val; - - raw_local_irq_save(flags); - val = v->counter; - v->counter = val += i; - raw_local_irq_restore(flags); - - return val; -} -#define atomic_add(i, v) (void) atomic_add_return(i, v) - -static inline int atomic_sub_return(int i, atomic_t *v) -{ - unsigned long flags; - int val; - - raw_local_irq_save(flags); - val = v->counter; - v->counter = val -= i; - raw_local_irq_restore(flags); - - return val; +#define ATOMIC_OP(op, c_op, asm_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ +} \ + +#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + int val; \ + \ + raw_local_irq_save(flags); \ + v->counter c_op i; \ + val = v->counter; \ + raw_local_irq_restore(flags); \ + \ + return val; \ } -#define atomic_sub(i, v) (void) atomic_sub_return(i, v) static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { @@ -228,6 +187,17 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #endif /* __LINUX_ARM_ARCH__ */ +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ + ATOMIC_OP_RETURN(op, c_op, asm_op) + +ATOMIC_OPS(add, +=, add) +ATOMIC_OPS(sub, -=, sub) + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) #define atomic_inc(v) atomic_add(1, v) @@ -300,89 +270,60 @@ static inline void atomic64_set(atomic64_t *v, long long i) } #endif -static inline void atomic64_add(long long i, atomic64_t *v) -{ - long long result; - unsigned long tmp; - - prefetchw(&v->counter); - __asm__ __volatile__("@ atomic64_add\n" -"1: ldrexd %0, %H0, [%3]\n" -" adds %Q0, %Q0, %Q4\n" -" adc %R0, %R0, %R4\n" -" strexd %1, %0, %H0, [%3]\n" -" teq %1, #0\n" -" bne 1b" - : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) - : "r" (&v->counter), "r" (i) - : "cc"); -} - -static inline long long atomic64_add_return(long long i, atomic64_t *v) -{ - long long result; - unsigned long tmp; - - smp_mb(); - prefetchw(&v->counter); - - __asm__ __volatile__("@ atomic64_add_return\n" -"1: ldrexd %0, %H0, [%3]\n" -" adds %Q0, %Q0, %Q4\n" -" adc %R0, %R0, %R4\n" -" strexd %1, %0, %H0, [%3]\n" -" teq %1, #0\n" -" bne 1b" - : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) - : "r" (&v->counter), "r" (i) - : "cc"); - - smp_mb(); - - return result; -} - -static inline void atomic64_sub(long long i, atomic64_t *v) -{ - long long result; - unsigned long tmp; - - prefetchw(&v->counter); - __asm__ __volatile__("@ atomic64_sub\n" -"1: ldrexd %0, %H0, [%3]\n" -" subs %Q0, %Q0, %Q4\n" -" sbc %R0, %R0, %R4\n" -" strexd %1, %0, %H0, [%3]\n" -" teq %1, #0\n" -" bne 1b" - : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) - : "r" (&v->counter), "r" (i) - : "cc"); +#define ATOMIC64_OP(op, op1, op2) \ +static inline void atomic64_##op(long long i, atomic64_t *v) \ +{ \ + long long result; \ + unsigned long tmp; \ + \ + prefetchw(&v->counter); \ + __asm__ __volatile__("@ atomic64_" #op "\n" \ +"1: ldrexd %0, %H0, [%3]\n" \ +" " #op1 " %Q0, %Q0, %Q4\n" \ +" " #op2 " %R0, %R0, %R4\n" \ +" strexd %1, %0, %H0, [%3]\n" \ +" teq %1, #0\n" \ +" bne 1b" \ + : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ + : "r" (&v->counter), "r" (i) \ + : "cc"); \ +} \ + +#define ATOMIC64_OP_RETURN(op, op1, op2) \ +static inline long long atomic64_##op##_return(long long i, atomic64_t *v) \ +{ \ + long long result; \ + unsigned long tmp; \ + \ + smp_mb(); \ + prefetchw(&v->counter); \ + \ + __asm__ __volatile__("@ atomic64_" #op "_return\n" \ +"1: ldrexd %0, %H0, [%3]\n" \ +" " #op1 " %Q0, %Q0, %Q4\n" \ +" " #op2 " %R0, %R0, %R4\n" \ +" strexd %1, %0, %H0, [%3]\n" \ +" teq %1, #0\n" \ +" bne 1b" \ + : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ + : "r" (&v->counter), "r" (i) \ + : "cc"); \ + \ + smp_mb(); \ + \ + return result; \ } -static inline long long atomic64_sub_return(long long i, atomic64_t *v) -{ - long long result; - unsigned long tmp; - - smp_mb(); - prefetchw(&v->counter); - - __asm__ __volatile__("@ atomic64_sub_return\n" -"1: ldrexd %0, %H0, [%3]\n" -" subs %Q0, %Q0, %Q4\n" -" sbc %R0, %R0, %R4\n" -" strexd %1, %0, %H0, [%3]\n" -" teq %1, #0\n" -" bne 1b" - : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) - : "r" (&v->counter), "r" (i) - : "cc"); +#define ATOMIC64_OPS(op, op1, op2) \ + ATOMIC64_OP(op, op1, op2) \ + ATOMIC64_OP_RETURN(op, op1, op2) - smp_mb(); +ATOMIC64_OPS(add, adds, adc) +ATOMIC64_OPS(sub, subs, sbc) - return result; -} +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP static inline long long atomic64_cmpxchg(atomic64_t *ptr, long long old, long long new) -- GitLab From 92ba1f530b4f90db78eb45f4b6598e75939146bd Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 23 Mar 2014 16:57:20 +0100 Subject: [PATCH 0284/5088] locking,arch,arm64: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Requires the asm_op due to eor. Signed-off-by: Peter Zijlstra Acked-by: Will Deacon Cc: Bjorn Helgaas Cc: Catalin Marinas Cc: Chen Gang Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/20140508135851.995123148@infradead.org Signed-off-by: Ingo Molnar --- arch/arm64/include/asm/atomic.h | 197 +++++++++++++------------------- 1 file changed, 80 insertions(+), 117 deletions(-) diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 65f1569ac96e..b83c325e587f 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -43,69 +43,51 @@ * store exclusive to ensure that these are atomic. We may loop * to ensure that the update happens. */ -static inline void atomic_add(int i, atomic_t *v) -{ - unsigned long tmp; - int result; - - asm volatile("// atomic_add\n" -"1: ldxr %w0, %2\n" -" add %w0, %w0, %w3\n" -" stxr %w1, %w0, %2\n" -" cbnz %w1, 1b" - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : "Ir" (i)); -} - -static inline int atomic_add_return(int i, atomic_t *v) -{ - unsigned long tmp; - int result; - - asm volatile("// atomic_add_return\n" -"1: ldxr %w0, %2\n" -" add %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; -} - -static inline void atomic_sub(int i, atomic_t *v) -{ - unsigned long tmp; - int result; - asm volatile("// atomic_sub\n" -"1: ldxr %w0, %2\n" -" sub %w0, %w0, %w3\n" -" stxr %w1, %w0, %2\n" -" cbnz %w1, 1b" - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : "Ir" (i)); +#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; \ } -static inline int atomic_sub_return(int i, atomic_t *v) -{ - unsigned long tmp; - int result; +#define ATOMIC_OPS(op, asm_op) \ + ATOMIC_OP(op, asm_op) \ + ATOMIC_OP_RETURN(op, asm_op) - asm volatile("// atomic_sub_return\n" -"1: ldxr %w0, %2\n" -" sub %w0, %w0, %w3\n" -" stlxr %w1, %w0, %2\n" -" cbnz %w1, 1b" - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : "Ir" (i) - : "memory"); +ATOMIC_OPS(add, add) +ATOMIC_OPS(sub, sub) - smp_mb(); - return result; -} +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) { @@ -160,69 +142,50 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #define atomic64_read(v) (*(volatile long *)&(v)->counter) #define atomic64_set(v,i) (((v)->counter) = (i)) -static inline void atomic64_add(u64 i, atomic64_t *v) -{ - long result; - unsigned long tmp; - - asm volatile("// atomic64_add\n" -"1: ldxr %0, %2\n" -" add %0, %0, %3\n" -" stxr %w1, %0, %2\n" -" cbnz %w1, 1b" - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : "Ir" (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; \ } -static inline long atomic64_add_return(long i, atomic64_t *v) -{ - long result; - unsigned long tmp; +#define ATOMIC64_OPS(op, asm_op) \ + ATOMIC64_OP(op, asm_op) \ + ATOMIC64_OP_RETURN(op, asm_op) - asm volatile("// atomic64_add_return\n" -"1: ldxr %0, %2\n" -" add %0, %0, %3\n" -" stlxr %w1, %0, %2\n" -" cbnz %w1, 1b" - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : "Ir" (i) - : "memory"); +ATOMIC64_OPS(add, add) +ATOMIC64_OPS(sub, sub) - smp_mb(); - return result; -} - -static inline void atomic64_sub(u64 i, atomic64_t *v) -{ - long result; - unsigned long tmp; - - asm volatile("// atomic64_sub\n" -"1: ldxr %0, %2\n" -" sub %0, %0, %3\n" -" stxr %w1, %0, %2\n" -" cbnz %w1, 1b" - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : "Ir" (i)); -} - -static inline long atomic64_sub_return(long i, atomic64_t *v) -{ - long result; - unsigned long tmp; - - asm volatile("// atomic64_sub_return\n" -"1: ldxr %0, %2\n" -" sub %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; -} +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) { -- GitLab From d325209b6000dcd13404ee946d2292e15a56718c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 9 Apr 2014 21:51:29 +0200 Subject: [PATCH 0285/5088] locking,arch,avr32: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Requires the asm_op because of eor. AVR32 is a bit special in that its ADD/SUB instructions are not symmetric. Its SUB instruction allows for an 21bit immediate. Signed-off-by: Peter Zijlstra Cc: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Cc: Hans-Christian Egtvedt Cc: Linus Torvalds Cc: Paul E. McKenney Link: http://lkml.kernel.org/r/20140531141445.GD16155@laptop.programming.kicks-ass.net Signed-off-by: Ingo Molnar --- arch/avr32/include/asm/atomic.h | 123 ++++++++++++++++---------------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h index 0780f3f2415b..83e980a4e483 100644 --- a/arch/avr32/include/asm/atomic.h +++ b/arch/avr32/include/asm/atomic.h @@ -22,30 +22,43 @@ #define atomic_read(v) (*(volatile int *)&(v)->counter) #define atomic_set(v, i) (((v)->counter) = i) +#define ATOMIC_OP_RETURN(op, asm_op, asm_con) \ +static inline int __atomic_##op##_return(int i, atomic_t *v) \ +{ \ + int result; \ + \ + asm volatile( \ + "/* atomic_" #op "_return */\n" \ + "1: ssrf 5\n" \ + " ld.w %0, %2\n" \ + " " #asm_op " %0, %3\n" \ + " stcond %1, %0\n" \ + " brne 1b" \ + : "=&r" (result), "=o" (v->counter) \ + : "m" (v->counter), #asm_con (i) \ + : "cc"); \ + \ + return result; \ +} + +ATOMIC_OP_RETURN(sub, sub, rKs21) +ATOMIC_OP_RETURN(add, add, r) + +#undef ATOMIC_OP_RETURN + /* - * atomic_sub_return - subtract the atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t + * Probably found the reason why we want to use sub with the signed 21-bit + * limit, it uses one less register than the add instruction that can add up to + * 32-bit values. * - * Atomically subtracts @i from @v. Returns the resulting value. + * Both instructions are 32-bit, to use a 16-bit instruction the immediate is + * very small; 4 bit. + * + * sub 32-bit, type IV, takes a register and subtracts a 21-bit immediate. + * add 32-bit, type II, adds two register values together. */ -static inline int atomic_sub_return(int i, atomic_t *v) -{ - int result; - - asm volatile( - "/* atomic_sub_return */\n" - "1: ssrf 5\n" - " ld.w %0, %2\n" - " sub %0, %3\n" - " stcond %1, %0\n" - " brne 1b" - : "=&r"(result), "=o"(v->counter) - : "m"(v->counter), "rKs21"(i) - : "cc"); - - return result; -} +#define IS_21BIT_CONST(i) \ + (__builtin_constant_p(i) && ((i) >= -1048575) && ((i) <= 1048576)) /* * atomic_add_return - add integer to atomic variable @@ -56,51 +69,25 @@ static inline int atomic_sub_return(int i, atomic_t *v) */ static inline int atomic_add_return(int i, atomic_t *v) { - int result; - - if (__builtin_constant_p(i) && (i >= -1048575) && (i <= 1048576)) - result = atomic_sub_return(-i, v); - else - asm volatile( - "/* atomic_add_return */\n" - "1: ssrf 5\n" - " ld.w %0, %1\n" - " add %0, %3\n" - " stcond %2, %0\n" - " brne 1b" - : "=&r"(result), "=o"(v->counter) - : "m"(v->counter), "r"(i) - : "cc", "memory"); + if (IS_21BIT_CONST(i)) + return __atomic_sub_return(-i, v); - return result; + return __atomic_add_return(i, v); } /* - * atomic_sub_unless - sub unless the number is a given value + * atomic_sub_return - subtract the atomic variable + * @i: integer value to subtract * @v: pointer of type atomic_t - * @a: the amount to subtract from v... - * @u: ...unless v is equal to u. * - * Atomically subtract @a from @v, so long as it was not @u. - * Returns the old value of @v. -*/ -static inline void atomic_sub_unless(atomic_t *v, int a, int u) + * Atomically subtracts @i from @v. Returns the resulting value. + */ +static inline int atomic_sub_return(int i, atomic_t *v) { - int tmp; + if (IS_21BIT_CONST(i)) + return __atomic_sub_return(i, v); - asm volatile( - "/* atomic_sub_unless */\n" - "1: ssrf 5\n" - " ld.w %0, %2\n" - " cp.w %0, %4\n" - " breq 1f\n" - " sub %0, %3\n" - " stcond %1, %0\n" - " brne 1b\n" - "1:" - : "=&r"(tmp), "=o"(v->counter) - : "m"(v->counter), "rKs21"(a), "rKs21"(u) - : "cc", "memory"); + return __atomic_add_return(-i, v); } /* @@ -116,9 +103,21 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) { int tmp, old = atomic_read(v); - if (__builtin_constant_p(a) && (a >= -1048575) && (a <= 1048576)) - atomic_sub_unless(v, -a, u); - else { + if (IS_21BIT_CONST(a)) { + asm volatile( + "/* __atomic_sub_unless */\n" + "1: ssrf 5\n" + " ld.w %0, %2\n" + " cp.w %0, %4\n" + " breq 1f\n" + " sub %0, %3\n" + " stcond %1, %0\n" + " brne 1b\n" + "1:" + : "=&r"(tmp), "=o"(v->counter) + : "m"(v->counter), "rKs21"(-a), "rKs21"(u) + : "cc", "memory"); + } else { asm volatile( "/* __atomic_add_unless */\n" "1: ssrf 5\n" @@ -137,6 +136,8 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) return old; } +#undef IS_21BIT_CONST + /* * atomic_sub_if_positive - conditionally subtract integer from atomic variable * @i: integer value to subtract -- GitLab From 7179e30ef66a5bae91592ae7fbacf3df6c627dd6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 23 Mar 2014 18:19:25 +0100 Subject: [PATCH 0286/5088] locking,arch,cris: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Acked-by: Jesper Nilsson Cc: Geert Uytterhoeven Cc: Linus Torvalds Cc: Mikael Starvik Cc: Paul E. McKenney Cc: linux-cris-kernel@axis.com Link: http://lkml.kernel.org/r/20140508135852.104572724@infradead.org Signed-off-by: Ingo Molnar --- arch/cris/include/asm/atomic.h | 57 +++++++++++++++------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/arch/cris/include/asm/atomic.h b/arch/cris/include/asm/atomic.h index aa429baebaf9..0033f9dfea24 100644 --- a/arch/cris/include/asm/atomic.h +++ b/arch/cris/include/asm/atomic.h @@ -22,43 +22,36 @@ /* These should be written in asm but we do it in C for now. */ -static inline void atomic_add(int i, volatile atomic_t *v) -{ - unsigned long flags; - cris_atomic_save(v, flags); - v->counter += i; - cris_atomic_restore(v, flags); +#define ATOMIC_OP(op, c_op) \ +static inline void atomic_##op(int i, volatile atomic_t *v) \ +{ \ + unsigned long flags; \ + cris_atomic_save(v, flags); \ + v->counter c_op i; \ + cris_atomic_restore(v, flags); \ +} \ + +#define ATOMIC_OP_RETURN(op, c_op) \ +static inline int atomic_##op##_return(int i, volatile atomic_t *v) \ +{ \ + unsigned long flags; \ + int retval; \ + cris_atomic_save(v, flags); \ + retval = (v->counter c_op i); \ + cris_atomic_restore(v, flags); \ + return retval; \ } -static inline void atomic_sub(int i, volatile atomic_t *v) -{ - unsigned long flags; - cris_atomic_save(v, flags); - v->counter -= i; - cris_atomic_restore(v, flags); -} +#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) -static inline int atomic_add_return(int i, volatile atomic_t *v) -{ - unsigned long flags; - int retval; - cris_atomic_save(v, flags); - retval = (v->counter += i); - cris_atomic_restore(v, flags); - return retval; -} +ATOMIC_OPS(add, +=) +ATOMIC_OPS(sub, -=) -#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP -static inline int atomic_sub_return(int i, volatile atomic_t *v) -{ - unsigned long flags; - int retval; - cris_atomic_save(v, flags); - retval = (v->counter -= i); - cris_atomic_restore(v, flags); - return retval; -} +#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) static inline int atomic_sub_and_test(int i, volatile atomic_t *v) { -- GitLab From 50f853e38b0b90a5703ab14b70e20eb5a8ccd5de Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 23 Mar 2014 18:20:26 +0100 Subject: [PATCH 0287/5088] locking,arch,hexagon: Fold atomic_ops OK, no LoC saved in this case because the !return variants were defined in terms of the return ops. Still do it because this also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Acked-by: Richard Kuo Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Vineet Gupta Cc: linux-hexagon@vger.kernel.org Link: http://lkml.kernel.org/r/20140508135852.171567636@infradead.org Signed-off-by: Ingo Molnar --- arch/hexagon/include/asm/atomic.h | 68 +++++++++++++++++-------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index de916b11bff5..93d07025f183 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h @@ -94,41 +94,47 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new) return __oldval; } -static inline int atomic_add_return(int i, atomic_t *v) -{ - int output; - - __asm__ __volatile__ ( - "1: %0 = memw_locked(%1);\n" - " %0 = add(%0,%2);\n" - " memw_locked(%1,P3)=%0;\n" - " if !P3 jump 1b;\n" - : "=&r" (output) - : "r" (&v->counter), "r" (i) - : "memory", "p3" - ); - return output; - +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + int output; \ + \ + __asm__ __volatile__ ( \ + "1: %0 = memw_locked(%1);\n" \ + " %0 = "#op "(%0,%2);\n" \ + " memw_locked(%1,P3)=%0;\n" \ + " if !P3 jump 1b;\n" \ + : "=&r" (output) \ + : "r" (&v->counter), "r" (i) \ + : "memory", "p3" \ + ); \ +} \ + +#define ATOMIC_OP_RETURN(op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + int output; \ + \ + __asm__ __volatile__ ( \ + "1: %0 = memw_locked(%1);\n" \ + " %0 = "#op "(%0,%2);\n" \ + " memw_locked(%1,P3)=%0;\n" \ + " if !P3 jump 1b;\n" \ + : "=&r" (output) \ + : "r" (&v->counter), "r" (i) \ + : "memory", "p3" \ + ); \ + return output; \ } -#define atomic_add(i, v) atomic_add_return(i, (v)) +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) -static inline int atomic_sub_return(int i, atomic_t *v) -{ - int output; - __asm__ __volatile__ ( - "1: %0 = memw_locked(%1);\n" - " %0 = sub(%0,%2);\n" - " memw_locked(%1,P3)=%0\n" - " if !P3 jump 1b;\n" - : "=&r" (output) - : "r" (&v->counter), "r" (i) - : "memory", "p3" - ); - return output; -} +ATOMIC_OPS(add) +ATOMIC_OPS(sub) -#define atomic_sub(i, v) atomic_sub_return(i, (v)) +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP /** * __atomic_add_unless - add unless the number is a given value -- GitLab From 08be2dab191431f23f5f98ba2db76513d0d853e7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 23 Mar 2014 18:20:30 +0100 Subject: [PATCH 0288/5088] locking,arch,ia64: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Cc: Fenghua Yu Cc: Linus Torvalds Cc: Akinobu Mita Cc: Paul E. McKenney Cc: Tony Luck Cc: linux-ia64@vger.kernel.org Link: http://lkml.kernel.org/r/20140508135852.245224472@infradead.org Signed-off-by: Ingo Molnar --- arch/ia64/include/asm/atomic.h | 188 +++++++++++++++------------------ 1 file changed, 86 insertions(+), 102 deletions(-) diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h index 0f8bf48dadf3..42919a831c6c 100644 --- a/arch/ia64/include/asm/atomic.h +++ b/arch/ia64/include/asm/atomic.h @@ -27,62 +27,94 @@ #define atomic_set(v,i) (((v)->counter) = (i)) #define atomic64_set(v,i) (((v)->counter) = (i)) -static __inline__ int -ia64_atomic_add (int i, atomic_t *v) -{ - __s32 old, new; - CMPXCHG_BUGCHECK_DECL - - do { - CMPXCHG_BUGCHECK(v); - old = atomic_read(v); - new = old + i; - } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); - return new; +#define ATOMIC_OP(op, c_op) \ +static __inline__ int \ +ia64_atomic_##op (int i, atomic_t *v) \ +{ \ + __s32 old, new; \ + CMPXCHG_BUGCHECK_DECL \ + \ + do { \ + CMPXCHG_BUGCHECK(v); \ + old = atomic_read(v); \ + new = old c_op i; \ + } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \ + return new; \ } -static __inline__ long -ia64_atomic64_add (__s64 i, atomic64_t *v) -{ - __s64 old, new; - CMPXCHG_BUGCHECK_DECL - - do { - CMPXCHG_BUGCHECK(v); - old = atomic64_read(v); - new = old + i; - } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); - return new; -} +ATOMIC_OP(add, +) +ATOMIC_OP(sub, -) -static __inline__ int -ia64_atomic_sub (int i, atomic_t *v) -{ - __s32 old, new; - CMPXCHG_BUGCHECK_DECL - - do { - CMPXCHG_BUGCHECK(v); - old = atomic_read(v); - new = old - i; - } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); - return new; -} +#undef ATOMIC_OP -static __inline__ long -ia64_atomic64_sub (__s64 i, atomic64_t *v) -{ - __s64 old, new; - CMPXCHG_BUGCHECK_DECL - - do { - CMPXCHG_BUGCHECK(v); - old = atomic64_read(v); - new = old - i; - } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); - return new; +#define atomic_add_return(i,v) \ +({ \ + int __ia64_aar_i = (i); \ + (__builtin_constant_p(i) \ + && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ + || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ + || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ + || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ + ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ + : ia64_atomic_add(__ia64_aar_i, v); \ +}) + +#define atomic_sub_return(i,v) \ +({ \ + int __ia64_asr_i = (i); \ + (__builtin_constant_p(i) \ + && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ + || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ + || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ + || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ + ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ + : ia64_atomic_sub(__ia64_asr_i, v); \ +}) + +#define ATOMIC64_OP(op, c_op) \ +static __inline__ long \ +ia64_atomic64_##op (__s64 i, atomic64_t *v) \ +{ \ + __s64 old, new; \ + CMPXCHG_BUGCHECK_DECL \ + \ + do { \ + CMPXCHG_BUGCHECK(v); \ + old = atomic64_read(v); \ + new = old c_op i; \ + } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \ + return new; \ } +ATOMIC64_OP(add, +) +ATOMIC64_OP(sub, -) + +#undef ATOMIC64_OP + +#define atomic64_add_return(i,v) \ +({ \ + long __ia64_aar_i = (i); \ + (__builtin_constant_p(i) \ + && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ + || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ + || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ + || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ + ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ + : ia64_atomic64_add(__ia64_aar_i, v); \ +}) + +#define atomic64_sub_return(i,v) \ +({ \ + long __ia64_asr_i = (i); \ + (__builtin_constant_p(i) \ + && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ + || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ + || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ + || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ + ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ + : ia64_atomic64_sub(__ia64_asr_i, v); \ +}) + #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) @@ -123,30 +155,6 @@ static __inline__ long atomic64_add_unless(atomic64_t *v, long a, long u) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) -#define atomic_add_return(i,v) \ -({ \ - int __ia64_aar_i = (i); \ - (__builtin_constant_p(i) \ - && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ - || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ - || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ - || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ - ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ - : ia64_atomic_add(__ia64_aar_i, v); \ -}) - -#define atomic64_add_return(i,v) \ -({ \ - long __ia64_aar_i = (i); \ - (__builtin_constant_p(i) \ - && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ - || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ - || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ - || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ - ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ - : ia64_atomic64_add(__ia64_aar_i, v); \ -}) - /* * Atomically add I to V and return TRUE if the resulting value is * negative. @@ -163,30 +171,6 @@ atomic64_add_negative (__s64 i, atomic64_t *v) return atomic64_add_return(i, v) < 0; } -#define atomic_sub_return(i,v) \ -({ \ - int __ia64_asr_i = (i); \ - (__builtin_constant_p(i) \ - && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ - || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ - || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ - || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ - ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ - : ia64_atomic_sub(__ia64_asr_i, v); \ -}) - -#define atomic64_sub_return(i,v) \ -({ \ - long __ia64_asr_i = (i); \ - (__builtin_constant_p(i) \ - && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ - || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ - || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ - || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ - ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ - : ia64_atomic64_sub(__ia64_asr_i, v); \ -}) - #define atomic_dec_return(v) atomic_sub_return(1, (v)) #define atomic_inc_return(v) atomic_add_return(1, (v)) #define atomic64_dec_return(v) atomic64_sub_return(1, (v)) @@ -199,13 +183,13 @@ atomic64_add_negative (__s64 i, atomic64_t *v) #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0) #define atomic64_inc_and_test(v) (atomic64_add_return(1, (v)) == 0) -#define atomic_add(i,v) atomic_add_return((i), (v)) -#define atomic_sub(i,v) atomic_sub_return((i), (v)) +#define atomic_add(i,v) (void)atomic_add_return((i), (v)) +#define atomic_sub(i,v) (void)atomic_sub_return((i), (v)) #define atomic_inc(v) atomic_add(1, (v)) #define atomic_dec(v) atomic_sub(1, (v)) -#define atomic64_add(i,v) atomic64_add_return((i), (v)) -#define atomic64_sub(i,v) atomic64_sub_return((i), (v)) +#define atomic64_add(i,v) (void)atomic64_add_return((i), (v)) +#define atomic64_sub(i,v) (void)atomic64_sub_return((i), (v)) #define atomic64_inc(v) atomic64_add(1, (v)) #define atomic64_dec(v) atomic64_sub(1, (v)) -- GitLab From c9ebe21b204f95e3aba84ee91c8b9347d73806f1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 23 Mar 2014 19:02:22 +0100 Subject: [PATCH 0289/5088] locking,arch,m32r: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Cc: Hirokazu Takata Cc: Linus Torvalds Cc: Paul E. McKenney Cc: linux-m32r-ja@ml.linux-m32r.org Cc: linux-m32r@ml.linux-m32r.org Link: http://lkml.kernel.org/r/20140508135852.318635136@infradead.org Signed-off-by: Ingo Molnar --- arch/m32r/include/asm/atomic.h | 143 +++++++++++++-------------------- 1 file changed, 57 insertions(+), 86 deletions(-) diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h index 8ad0ed4182a5..3946b2c8d971 100644 --- a/arch/m32r/include/asm/atomic.h +++ b/arch/m32r/include/asm/atomic.h @@ -39,85 +39,64 @@ */ #define atomic_set(v,i) (((v)->counter) = (i)) -/** - * atomic_add_return - add integer to atomic variable and return it - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v and return (@i + @v). - */ -static __inline__ int atomic_add_return(int i, atomic_t *v) -{ - unsigned long flags; - int result; - - local_irq_save(flags); - __asm__ __volatile__ ( - "# atomic_add_return \n\t" - DCACHE_CLEAR("%0", "r4", "%1") - M32R_LOCK" %0, @%1; \n\t" - "add %0, %2; \n\t" - M32R_UNLOCK" %0, @%1; \n\t" - : "=&r" (result) - : "r" (&v->counter), "r" (i) - : "memory" #ifdef CONFIG_CHIP_M32700_TS1 - , "r4" -#endif /* CONFIG_CHIP_M32700_TS1 */ - ); - local_irq_restore(flags); - - return result; +#define __ATOMIC_CLOBBER , "r4" +#else +#define __ATOMIC_CLOBBER +#endif + +#define ATOMIC_OP(op) \ +static __inline__ void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + int result; \ + \ + local_irq_save(flags); \ + __asm__ __volatile__ ( \ + "# atomic_" #op " \n\t" \ + DCACHE_CLEAR("%0", "r4", "%1") \ + M32R_LOCK" %0, @%1; \n\t" \ + #op " %0, %2; \n\t" \ + M32R_UNLOCK" %0, @%1; \n\t" \ + : "=&r" (result) \ + : "r" (&v->counter), "r" (i) \ + : "memory" \ + __ATOMIC_CLOBBER \ + ); \ + local_irq_restore(flags); \ +} \ + +#define ATOMIC_OP_RETURN(op) \ +static __inline__ int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + int result; \ + \ + local_irq_save(flags); \ + __asm__ __volatile__ ( \ + "# atomic_" #op "_return \n\t" \ + DCACHE_CLEAR("%0", "r4", "%1") \ + M32R_LOCK" %0, @%1; \n\t" \ + #op " %0, %2; \n\t" \ + M32R_UNLOCK" %0, @%1; \n\t" \ + : "=&r" (result) \ + : "r" (&v->counter), "r" (i) \ + : "memory" \ + __ATOMIC_CLOBBER \ + ); \ + local_irq_restore(flags); \ + \ + return result; \ } -/** - * atomic_sub_return - subtract integer from atomic variable and return it - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v and return (@v - @i). - */ -static __inline__ int atomic_sub_return(int i, atomic_t *v) -{ - unsigned long flags; - int result; - - local_irq_save(flags); - __asm__ __volatile__ ( - "# atomic_sub_return \n\t" - DCACHE_CLEAR("%0", "r4", "%1") - M32R_LOCK" %0, @%1; \n\t" - "sub %0, %2; \n\t" - M32R_UNLOCK" %0, @%1; \n\t" - : "=&r" (result) - : "r" (&v->counter), "r" (i) - : "memory" -#ifdef CONFIG_CHIP_M32700_TS1 - , "r4" -#endif /* CONFIG_CHIP_M32700_TS1 */ - ); - local_irq_restore(flags); - - return result; -} +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) -/** - * atomic_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v. - */ -#define atomic_add(i,v) ((void) atomic_add_return((i), (v))) +ATOMIC_OPS(add) +ATOMIC_OPS(sub) -/** - * atomic_sub - subtract the atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v. - */ -#define atomic_sub(i,v) ((void) atomic_sub_return((i), (v))) +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP /** * atomic_sub_and_test - subtract value from variable and test result @@ -151,9 +130,7 @@ static __inline__ int atomic_inc_return(atomic_t *v) : "=&r" (result) : "r" (&v->counter) : "memory" -#ifdef CONFIG_CHIP_M32700_TS1 - , "r4" -#endif /* CONFIG_CHIP_M32700_TS1 */ + __ATOMIC_CLOBBER ); local_irq_restore(flags); @@ -181,9 +158,7 @@ static __inline__ int atomic_dec_return(atomic_t *v) : "=&r" (result) : "r" (&v->counter) : "memory" -#ifdef CONFIG_CHIP_M32700_TS1 - , "r4" -#endif /* CONFIG_CHIP_M32700_TS1 */ + __ATOMIC_CLOBBER ); local_irq_restore(flags); @@ -280,9 +255,7 @@ static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *addr) : "=&r" (tmp) : "r" (addr), "r" (~mask) : "memory" -#ifdef CONFIG_CHIP_M32700_TS1 - , "r5" -#endif /* CONFIG_CHIP_M32700_TS1 */ + __ATOMIC_CLOBBER ); local_irq_restore(flags); } @@ -302,9 +275,7 @@ static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *addr) : "=&r" (tmp) : "r" (addr), "r" (mask) : "memory" -#ifdef CONFIG_CHIP_M32700_TS1 - , "r5" -#endif /* CONFIG_CHIP_M32700_TS1 */ + __ATOMIC_CLOBBER ); local_irq_restore(flags); } -- GitLab From d839bae4269aea46bff4133066a411cfba5c7c46 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 23 Mar 2014 19:06:34 +0100 Subject: [PATCH 0290/5088] locking,arch,m68k: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Requires asm_op due to eor. Signed-off-by: Peter Zijlstra Acked-by: Geert Uytterhoeven Cc: Linus Torvalds Cc: Paul E. McKenney Cc: linux-m68k@lists.linux-m68k.org Link: http://lkml.kernel.org/r/20140509091646.GO30445@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar --- arch/m68k/include/asm/atomic.h | 109 ++++++++++++++------------------- 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index 55695212a2ae..663d4ba2462c 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -30,16 +30,57 @@ #define ASM_DI "di" #endif -static inline void atomic_add(int i, atomic_t *v) -{ - __asm__ __volatile__("addl %1,%0" : "+m" (*v) : ASM_DI (i)); +#define ATOMIC_OP(op, c_op, asm_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + __asm__ __volatile__(#asm_op "l %1,%0" : "+m" (*v) : ASM_DI (i));\ +} \ + +#ifdef CONFIG_RMW_INSNS + +#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + int t, tmp; \ + \ + __asm__ __volatile__( \ + "1: movel %2,%1\n" \ + " " #asm_op "l %3,%1\n" \ + " casl %2,%1,%0\n" \ + " jne 1b" \ + : "+m" (*v), "=&d" (t), "=&d" (tmp) \ + : "g" (i), "2" (atomic_read(v))); \ + return t; \ } -static inline void atomic_sub(int i, atomic_t *v) -{ - __asm__ __volatile__("subl %1,%0" : "+m" (*v) : ASM_DI (i)); +#else + +#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ +static inline int atomic_##op##_return(int i, atomic_t * v) \ +{ \ + unsigned long flags; \ + int t; \ + \ + local_irq_save(flags); \ + t = (v->counter c_op i); \ + local_irq_restore(flags); \ + \ + return t; \ } +#endif /* CONFIG_RMW_INSNS */ + +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ + ATOMIC_OP_RETURN(op, c_op, asm_op) + +ATOMIC_OPS(add, +=, add) +ATOMIC_OPS(sub, -=, sub) + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + static inline void atomic_inc(atomic_t *v) { __asm__ __volatile__("addql #1,%0" : "+m" (*v)); @@ -76,67 +117,11 @@ static inline int atomic_inc_and_test(atomic_t *v) #ifdef CONFIG_RMW_INSNS -static inline int atomic_add_return(int i, atomic_t *v) -{ - int t, tmp; - - __asm__ __volatile__( - "1: movel %2,%1\n" - " addl %3,%1\n" - " casl %2,%1,%0\n" - " jne 1b" - : "+m" (*v), "=&d" (t), "=&d" (tmp) - : "g" (i), "2" (atomic_read(v))); - return t; -} - -static inline int atomic_sub_return(int i, atomic_t *v) -{ - int t, tmp; - - __asm__ __volatile__( - "1: movel %2,%1\n" - " subl %3,%1\n" - " casl %2,%1,%0\n" - " jne 1b" - : "+m" (*v), "=&d" (t), "=&d" (tmp) - : "g" (i), "2" (atomic_read(v))); - return t; -} - #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) #else /* !CONFIG_RMW_INSNS */ -static inline int atomic_add_return(int i, atomic_t * v) -{ - unsigned long flags; - int t; - - local_irq_save(flags); - t = atomic_read(v); - t += i; - atomic_set(v, t); - local_irq_restore(flags); - - return t; -} - -static inline int atomic_sub_return(int i, atomic_t * v) -{ - unsigned long flags; - int t; - - local_irq_save(flags); - t = atomic_read(v); - t -= i; - atomic_set(v, t); - local_irq_restore(flags); - - return t; -} - static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { unsigned long flags; -- GitLab From d6dfe2509da935a15583cace7cd3837b1e8addef Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 23 Mar 2014 19:08:25 +0100 Subject: [PATCH 0291/5088] locking,arch,metag: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Acked-by: James Hogan Cc: Linus Torvalds Cc: linux-metag@vger.kernel.org Link: http://lkml.kernel.org/r/20140508135852.453864110@infradead.org Signed-off-by: Ingo Molnar --- arch/metag/include/asm/atomic_lnkget.h | 121 ++++++++++--------------- arch/metag/include/asm/atomic_lock1.h | 76 +++++++--------- 2 files changed, 77 insertions(+), 120 deletions(-) diff --git a/arch/metag/include/asm/atomic_lnkget.h b/arch/metag/include/asm/atomic_lnkget.h index d2e60a18986c..948d8688643c 100644 --- a/arch/metag/include/asm/atomic_lnkget.h +++ b/arch/metag/include/asm/atomic_lnkget.h @@ -27,85 +27,56 @@ static inline int atomic_read(const atomic_t *v) return temp; } -static inline void atomic_add(int i, atomic_t *v) -{ - int temp; - - asm volatile ( - "1: LNKGETD %0, [%1]\n" - " ADD %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" (i) - : "cc"); +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + int temp; \ + \ + asm volatile ( \ + "1: LNKGETD %0, [%1]\n" \ + " " #op " %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" (i) \ + : "cc"); \ +} \ + +#define ATOMIC_OP_RETURN(op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + int result, temp; \ + \ + smp_mb(); \ + \ + asm volatile ( \ + "1: LNKGETD %1, [%2]\n" \ + " " #op " %1, %1, %3\n" \ + " LNKSETD [%2], %1\n" \ + " DEFR %0, TXSTAT\n" \ + " ANDT %0, %0, #HI(0x3f000000)\n" \ + " CMPT %0, #HI(0x02000000)\n" \ + " BNZ 1b\n" \ + : "=&d" (temp), "=&da" (result) \ + : "da" (&v->counter), "bd" (i) \ + : "cc"); \ + \ + smp_mb(); \ + \ + return result; \ } -static inline void atomic_sub(int i, atomic_t *v) -{ - int temp; +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) - asm volatile ( - "1: LNKGETD %0, [%1]\n" - " SUB %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" (i) - : "cc"); -} +ATOMIC_OPS(add) +ATOMIC_OPS(sub) -static inline int atomic_add_return(int i, atomic_t *v) -{ - int result, temp; - - smp_mb(); - - asm volatile ( - "1: LNKGETD %1, [%2]\n" - " ADD %1, %1, %3\n" - " LNKSETD [%2], %1\n" - " DEFR %0, TXSTAT\n" - " ANDT %0, %0, #HI(0x3f000000)\n" - " CMPT %0, #HI(0x02000000)\n" - " BNZ 1b\n" - : "=&d" (temp), "=&da" (result) - : "da" (&v->counter), "bd" (i) - : "cc"); - - smp_mb(); - - return result; -} - -static inline int atomic_sub_return(int i, atomic_t *v) -{ - int result, temp; - - smp_mb(); - - asm volatile ( - "1: LNKGETD %1, [%2]\n" - " SUB %1, %1, %3\n" - " LNKSETD [%2], %1\n" - " DEFR %0, TXSTAT\n" - " ANDT %0, %0, #HI(0x3f000000)\n" - " CMPT %0, #HI(0x02000000)\n" - " BNZ 1b\n" - : "=&d" (temp), "=&da" (result) - : "da" (&v->counter), "bd" (i) - : "cc"); - - smp_mb(); - - return result; -} +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) { diff --git a/arch/metag/include/asm/atomic_lock1.h b/arch/metag/include/asm/atomic_lock1.h index e578955e674b..f5d5898c1020 100644 --- a/arch/metag/include/asm/atomic_lock1.h +++ b/arch/metag/include/asm/atomic_lock1.h @@ -37,55 +37,41 @@ static inline int atomic_set(atomic_t *v, int i) return i; } -static inline void atomic_add(int i, atomic_t *v) -{ - unsigned long flags; - - __global_lock1(flags); - fence(); - v->counter += i; - __global_unlock1(flags); +#define ATOMIC_OP(op, c_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + \ + __global_lock1(flags); \ + fence(); \ + v->counter c_op i; \ + __global_unlock1(flags); \ +} \ + +#define ATOMIC_OP_RETURN(op, c_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long result; \ + unsigned long flags; \ + \ + __global_lock1(flags); \ + result = v->counter; \ + result c_op i; \ + fence(); \ + v->counter = result; \ + __global_unlock1(flags); \ + \ + return result; \ } -static inline void atomic_sub(int i, atomic_t *v) -{ - unsigned long flags; +#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) - __global_lock1(flags); - fence(); - v->counter -= i; - __global_unlock1(flags); -} - -static inline int atomic_add_return(int i, atomic_t *v) -{ - unsigned long result; - unsigned long flags; +ATOMIC_OPS(add, +=) +ATOMIC_OPS(sub, -=) - __global_lock1(flags); - result = v->counter; - result += i; - fence(); - v->counter = result; - __global_unlock1(flags); - - return result; -} - -static inline int atomic_sub_return(int i, atomic_t *v) -{ - unsigned long result; - unsigned long flags; - - __global_lock1(flags); - result = v->counter; - result -= i; - fence(); - v->counter = result; - __global_unlock1(flags); - - return result; -} +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) { -- GitLab From ef31563e950c60bb41b97c2b61c32de874f3c949 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 26 Mar 2014 17:56:43 +0100 Subject: [PATCH 0292/5088] locking,arch,mips: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Cc: Maciej W. Rozycki Cc: Paul E. McKenney Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Link: http://lkml.kernel.org/r/20140508135852.521548500@infradead.org Signed-off-by: Ingo Molnar --- arch/mips/include/asm/atomic.h | 557 +++++++++++---------------------- 1 file changed, 187 insertions(+), 370 deletions(-) diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 37b2befe651a..476fe3b5dfc6 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -40,195 +40,103 @@ */ #define atomic_set(v, i) ((v)->counter = (i)) -/* - * atomic_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v. - */ -static __inline__ void atomic_add(int i, atomic_t * v) -{ - if (kernel_uses_llsc && R10000_LLSC_WAR) { - int temp; - - __asm__ __volatile__( - " .set arch=r4000 \n" - "1: ll %0, %1 # atomic_add \n" - " addu %0, %2 \n" - " sc %0, %1 \n" - " beqzl %0, 1b \n" - " .set mips0 \n" - : "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } else if (kernel_uses_llsc) { - int temp; - - do { - __asm__ __volatile__( - " .set arch=r4000 \n" - " ll %0, %1 # atomic_add \n" - " addu %0, %2 \n" - " sc %0, %1 \n" - " .set mips0 \n" - : "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } while (unlikely(!temp)); - } else { - unsigned long flags; - - raw_local_irq_save(flags); - v->counter += i; - raw_local_irq_restore(flags); - } -} - -/* - * atomic_sub - subtract the atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v. - */ -static __inline__ void atomic_sub(int i, atomic_t * v) -{ - if (kernel_uses_llsc && R10000_LLSC_WAR) { - int temp; - - __asm__ __volatile__( - " .set arch=r4000 \n" - "1: ll %0, %1 # atomic_sub \n" - " subu %0, %2 \n" - " sc %0, %1 \n" - " beqzl %0, 1b \n" - " .set mips0 \n" - : "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } else if (kernel_uses_llsc) { - int temp; - - do { - __asm__ __volatile__( - " .set arch=r4000 \n" - " ll %0, %1 # atomic_sub \n" - " subu %0, %2 \n" - " sc %0, %1 \n" - " .set mips0 \n" - : "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } while (unlikely(!temp)); - } else { - unsigned long flags; - - raw_local_irq_save(flags); - v->counter -= i; - raw_local_irq_restore(flags); - } -} - -/* - * Same as above, but return the result value - */ -static __inline__ int atomic_add_return(int i, atomic_t * v) -{ - int result; - - smp_mb__before_llsc(); - - if (kernel_uses_llsc && R10000_LLSC_WAR) { - int temp; - - __asm__ __volatile__( - " .set arch=r4000 \n" - "1: ll %1, %2 # atomic_add_return \n" - " addu %0, %1, %3 \n" - " sc %0, %2 \n" - " beqzl %0, 1b \n" - " addu %0, %1, %3 \n" - " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } else if (kernel_uses_llsc) { - int temp; - - do { - __asm__ __volatile__( - " .set arch=r4000 \n" - " ll %1, %2 # atomic_add_return \n" - " addu %0, %1, %3 \n" - " sc %0, %2 \n" - " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } while (unlikely(!result)); - - result = temp + i; - } else { - unsigned long flags; - - raw_local_irq_save(flags); - result = v->counter; - result += i; - v->counter = result; - raw_local_irq_restore(flags); - } - - smp_llsc_mb(); - - return result; +#define ATOMIC_OP(op, c_op, asm_op) \ +static __inline__ void atomic_##op(int i, atomic_t * v) \ +{ \ + if (kernel_uses_llsc && R10000_LLSC_WAR) { \ + int temp; \ + \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + "1: ll %0, %1 # atomic_" #op " \n" \ + " " #asm_op " %0, %2 \n" \ + " sc %0, %1 \n" \ + " beqzl %0, 1b \n" \ + " .set mips0 \n" \ + : "=&r" (temp), "+m" (v->counter) \ + : "Ir" (i)); \ + } else if (kernel_uses_llsc) { \ + int temp; \ + \ + do { \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + " ll %0, %1 # atomic_" #op "\n" \ + " " #asm_op " %0, %2 \n" \ + " sc %0, %1 \n" \ + " .set mips0 \n" \ + : "=&r" (temp), "+m" (v->counter) \ + : "Ir" (i)); \ + } while (unlikely(!temp)); \ + } else { \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ + } \ +} \ + +#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ +static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ +{ \ + int result; \ + \ + smp_mb__before_llsc(); \ + \ + if (kernel_uses_llsc && R10000_LLSC_WAR) { \ + int temp; \ + \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + "1: ll %1, %2 # atomic_" #op "_return \n" \ + " " #asm_op " %0, %1, %3 \n" \ + " sc %0, %2 \n" \ + " beqzl %0, 1b \n" \ + " addu %0, %1, %3 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), "+m" (v->counter) \ + : "Ir" (i)); \ + } else if (kernel_uses_llsc) { \ + int temp; \ + \ + do { \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + " ll %1, %2 # atomic_" #op "_return \n" \ + " " #asm_op " %0, %1, %3 \n" \ + " sc %0, %2 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), "+m" (v->counter) \ + : "Ir" (i)); \ + } while (unlikely(!result)); \ + \ + result = temp + i; \ + } else { \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + result = v->counter; \ + result c_op i; \ + v->counter = result; \ + raw_local_irq_restore(flags); \ + } \ + \ + smp_llsc_mb(); \ + \ + return result; \ } -static __inline__ int atomic_sub_return(int i, atomic_t * v) -{ - int result; +#define ATOMIC_OPS(op, c_op, asm_op) \ + ATOMIC_OP(op, c_op, asm_op) \ + ATOMIC_OP_RETURN(op, c_op, asm_op) - smp_mb__before_llsc(); +ATOMIC_OPS(add, +=, addu) +ATOMIC_OPS(sub, -=, subu) - if (kernel_uses_llsc && R10000_LLSC_WAR) { - int temp; - - __asm__ __volatile__( - " .set arch=r4000 \n" - "1: ll %1, %2 # atomic_sub_return \n" - " subu %0, %1, %3 \n" - " sc %0, %2 \n" - " beqzl %0, 1b \n" - " subu %0, %1, %3 \n" - " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "=m" (v->counter) - : "Ir" (i), "m" (v->counter) - : "memory"); - - result = temp - i; - } else if (kernel_uses_llsc) { - int temp; - - do { - __asm__ __volatile__( - " .set arch=r4000 \n" - " ll %1, %2 # atomic_sub_return \n" - " subu %0, %1, %3 \n" - " sc %0, %2 \n" - " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } while (unlikely(!result)); - - result = temp - i; - } else { - unsigned long flags; - - raw_local_irq_save(flags); - result = v->counter; - result -= i; - v->counter = result; - raw_local_irq_restore(flags); - } - - smp_llsc_mb(); - - return result; -} +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP /* * atomic_sub_if_positive - conditionally subtract integer from atomic variable @@ -407,195 +315,104 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) */ #define atomic64_set(v, i) ((v)->counter = (i)) -/* - * atomic64_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic64_t - * - * Atomically adds @i to @v. - */ -static __inline__ void atomic64_add(long i, atomic64_t * v) -{ - if (kernel_uses_llsc && R10000_LLSC_WAR) { - long temp; - - __asm__ __volatile__( - " .set arch=r4000 \n" - "1: lld %0, %1 # atomic64_add \n" - " daddu %0, %2 \n" - " scd %0, %1 \n" - " beqzl %0, 1b \n" - " .set mips0 \n" - : "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } else if (kernel_uses_llsc) { - long temp; - - do { - __asm__ __volatile__( - " .set arch=r4000 \n" - " lld %0, %1 # atomic64_add \n" - " daddu %0, %2 \n" - " scd %0, %1 \n" - " .set mips0 \n" - : "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } while (unlikely(!temp)); - } else { - unsigned long flags; - - raw_local_irq_save(flags); - v->counter += i; - raw_local_irq_restore(flags); - } +#define ATOMIC64_OP(op, c_op, asm_op) \ +static __inline__ void atomic64_##op(long i, atomic64_t * v) \ +{ \ + if (kernel_uses_llsc && R10000_LLSC_WAR) { \ + long temp; \ + \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + "1: lld %0, %1 # atomic64_" #op " \n" \ + " " #asm_op " %0, %2 \n" \ + " scd %0, %1 \n" \ + " beqzl %0, 1b \n" \ + " .set mips0 \n" \ + : "=&r" (temp), "+m" (v->counter) \ + : "Ir" (i)); \ + } else if (kernel_uses_llsc) { \ + long temp; \ + \ + do { \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + " lld %0, %1 # atomic64_" #op "\n" \ + " " #asm_op " %0, %2 \n" \ + " scd %0, %1 \n" \ + " .set mips0 \n" \ + : "=&r" (temp), "+m" (v->counter) \ + : "Ir" (i)); \ + } while (unlikely(!temp)); \ + } else { \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ + } \ +} \ + +#define ATOMIC64_OP_RETURN(op, c_op, asm_op) \ +static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ +{ \ + long result; \ + \ + smp_mb__before_llsc(); \ + \ + if (kernel_uses_llsc && R10000_LLSC_WAR) { \ + long temp; \ + \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + "1: lld %1, %2 # atomic64_" #op "_return\n" \ + " " #asm_op " %0, %1, %3 \n" \ + " scd %0, %2 \n" \ + " beqzl %0, 1b \n" \ + " " #asm_op " %0, %1, %3 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), "+m" (v->counter) \ + : "Ir" (i)); \ + } else if (kernel_uses_llsc) { \ + long temp; \ + \ + do { \ + __asm__ __volatile__( \ + " .set arch=r4000 \n" \ + " lld %1, %2 # atomic64_" #op "_return\n" \ + " " #asm_op " %0, %1, %3 \n" \ + " scd %0, %2 \n" \ + " .set mips0 \n" \ + : "=&r" (result), "=&r" (temp), "=m" (v->counter) \ + : "Ir" (i), "m" (v->counter) \ + : "memory"); \ + } while (unlikely(!result)); \ + \ + result = temp + i; \ + } else { \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + result = v->counter; \ + result c_op i; \ + v->counter = result; \ + raw_local_irq_restore(flags); \ + } \ + \ + smp_llsc_mb(); \ + \ + return result; \ } -/* - * atomic64_sub - subtract the atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic64_t - * - * Atomically subtracts @i from @v. - */ -static __inline__ void atomic64_sub(long i, atomic64_t * v) -{ - if (kernel_uses_llsc && R10000_LLSC_WAR) { - long temp; - - __asm__ __volatile__( - " .set arch=r4000 \n" - "1: lld %0, %1 # atomic64_sub \n" - " dsubu %0, %2 \n" - " scd %0, %1 \n" - " beqzl %0, 1b \n" - " .set mips0 \n" - : "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } else if (kernel_uses_llsc) { - long temp; - - do { - __asm__ __volatile__( - " .set arch=r4000 \n" - " lld %0, %1 # atomic64_sub \n" - " dsubu %0, %2 \n" - " scd %0, %1 \n" - " .set mips0 \n" - : "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } while (unlikely(!temp)); - } else { - unsigned long flags; - - raw_local_irq_save(flags); - v->counter -= i; - raw_local_irq_restore(flags); - } -} - -/* - * Same as above, but return the result value - */ -static __inline__ long atomic64_add_return(long i, atomic64_t * v) -{ - long result; +#define ATOMIC64_OPS(op, c_op, asm_op) \ + ATOMIC64_OP(op, c_op, asm_op) \ + ATOMIC64_OP_RETURN(op, c_op, asm_op) - smp_mb__before_llsc(); +ATOMIC64_OPS(add, +=, daddu) +ATOMIC64_OPS(sub, -=, dsubu) - if (kernel_uses_llsc && R10000_LLSC_WAR) { - long temp; - - __asm__ __volatile__( - " .set arch=r4000 \n" - "1: lld %1, %2 # atomic64_add_return \n" - " daddu %0, %1, %3 \n" - " scd %0, %2 \n" - " beqzl %0, 1b \n" - " daddu %0, %1, %3 \n" - " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "+m" (v->counter) - : "Ir" (i)); - } else if (kernel_uses_llsc) { - long temp; - - do { - __asm__ __volatile__( - " .set arch=r4000 \n" - " lld %1, %2 # atomic64_add_return \n" - " daddu %0, %1, %3 \n" - " scd %0, %2 \n" - " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "=m" (v->counter) - : "Ir" (i), "m" (v->counter) - : "memory"); - } while (unlikely(!result)); - - result = temp + i; - } else { - unsigned long flags; - - raw_local_irq_save(flags); - result = v->counter; - result += i; - v->counter = result; - raw_local_irq_restore(flags); - } - - smp_llsc_mb(); - - return result; -} - -static __inline__ long atomic64_sub_return(long i, atomic64_t * v) -{ - long result; - - smp_mb__before_llsc(); - - if (kernel_uses_llsc && R10000_LLSC_WAR) { - long temp; - - __asm__ __volatile__( - " .set arch=r4000 \n" - "1: lld %1, %2 # atomic64_sub_return \n" - " dsubu %0, %1, %3 \n" - " scd %0, %2 \n" - " beqzl %0, 1b \n" - " dsubu %0, %1, %3 \n" - " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "=m" (v->counter) - : "Ir" (i), "m" (v->counter) - : "memory"); - } else if (kernel_uses_llsc) { - long temp; - - do { - __asm__ __volatile__( - " .set arch=r4000 \n" - " lld %1, %2 # atomic64_sub_return \n" - " dsubu %0, %1, %3 \n" - " scd %0, %2 \n" - " .set mips0 \n" - : "=&r" (result), "=&r" (temp), "=m" (v->counter) - : "Ir" (i), "m" (v->counter) - : "memory"); - } while (unlikely(!result)); - - result = temp - i; - } else { - unsigned long flags; - - raw_local_irq_save(flags); - result = v->counter; - result -= i; - v->counter = result; - raw_local_irq_restore(flags); - } - - smp_llsc_mb(); - - return result; -} +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP /* * atomic64_sub_if_positive - conditionally subtract integer from atomic variable -- GitLab From e69a0ef76627005e3e83d0e086e6bb1d247bb65b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 26 Mar 2014 17:59:04 +0100 Subject: [PATCH 0293/5088] locking,arch,mn10300: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Cc: David Howells Cc: Koichi Yasutake Cc: Linus Torvalds Cc: Paul E. McKenney Cc: linux-am33-list@redhat.com Link: http://lkml.kernel.org/r/20140508135852.605324173@infradead.org Signed-off-by: Ingo Molnar --- arch/mn10300/include/asm/atomic.h | 125 ++++++++++-------------------- 1 file changed, 42 insertions(+), 83 deletions(-) diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h index cadeb1e2cdfc..5be655e83e70 100644 --- a/arch/mn10300/include/asm/atomic.h +++ b/arch/mn10300/include/asm/atomic.h @@ -33,7 +33,6 @@ * @v: pointer of type atomic_t * * Atomically reads the value of @v. Note that the guaranteed - * useful range of an atomic_t is only 24 bits. */ #define atomic_read(v) (ACCESS_ONCE((v)->counter)) @@ -43,102 +42,62 @@ * @i: required value * * Atomically sets the value of @v to @i. Note that the guaranteed - * useful range of an atomic_t is only 24 bits. */ #define atomic_set(v, i) (((v)->counter) = (i)) -/** - * atomic_add_return - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v and returns the result - * Note that the guaranteed useful range of an atomic_t is only 24 bits. - */ -static inline int atomic_add_return(int i, atomic_t *v) -{ - int retval; -#ifdef CONFIG_SMP - int status; - - asm volatile( - "1: mov %4,(_AAR,%3) \n" - " mov (_ADR,%3),%1 \n" - " add %5,%1 \n" - " mov %1,(_ADR,%3) \n" - " mov (_ADR,%3),%0 \n" /* flush */ - " mov (_ASR,%3),%0 \n" - " or %0,%0 \n" - " bne 1b \n" - : "=&r"(status), "=&r"(retval), "=m"(v->counter) - : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) - : "memory", "cc"); - -#else - unsigned long flags; +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + int retval, status; \ + \ + asm volatile( \ + "1: mov %4,(_AAR,%3) \n" \ + " mov (_ADR,%3),%1 \n" \ + " " #op " %5,%1 \n" \ + " mov %1,(_ADR,%3) \n" \ + " mov (_ADR,%3),%0 \n" /* flush */ \ + " mov (_ASR,%3),%0 \n" \ + " or %0,%0 \n" \ + " bne 1b \n" \ + : "=&r"(status), "=&r"(retval), "=m"(v->counter) \ + : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) \ + : "memory", "cc"); \ +} - flags = arch_local_cli_save(); - retval = v->counter; - retval += i; - v->counter = retval; - arch_local_irq_restore(flags); -#endif - return retval; +#define ATOMIC_OP_RETURN(op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + int retval, status; \ + \ + asm volatile( \ + "1: mov %4,(_AAR,%3) \n" \ + " mov (_ADR,%3),%1 \n" \ + " " #op " %5,%1 \n" \ + " mov %1,(_ADR,%3) \n" \ + " mov (_ADR,%3),%0 \n" /* flush */ \ + " mov (_ASR,%3),%0 \n" \ + " or %0,%0 \n" \ + " bne 1b \n" \ + : "=&r"(status), "=&r"(retval), "=m"(v->counter) \ + : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) \ + : "memory", "cc"); \ + return retval; \ } -/** - * atomic_sub_return - subtract integer from atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v and returns the result - * Note that the guaranteed useful range of an atomic_t is only 24 bits. - */ -static inline int atomic_sub_return(int i, atomic_t *v) -{ - int retval; -#ifdef CONFIG_SMP - int status; +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) - asm volatile( - "1: mov %4,(_AAR,%3) \n" - " mov (_ADR,%3),%1 \n" - " sub %5,%1 \n" - " mov %1,(_ADR,%3) \n" - " mov (_ADR,%3),%0 \n" /* flush */ - " mov (_ASR,%3),%0 \n" - " or %0,%0 \n" - " bne 1b \n" - : "=&r"(status), "=&r"(retval), "=m"(v->counter) - : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) - : "memory", "cc"); +ATOMIC_OPS(add) +ATOMIC_OPS(sub) -#else - unsigned long flags; - flags = arch_local_cli_save(); - retval = v->counter; - retval -= i; - v->counter = retval; - arch_local_irq_restore(flags); -#endif - return retval; -} +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP static inline int atomic_add_negative(int i, atomic_t *v) { return atomic_add_return(i, v) < 0; } -static inline void atomic_add(int i, atomic_t *v) -{ - atomic_add_return(i, v); -} - -static inline void atomic_sub(int i, atomic_t *v) -{ - atomic_sub_return(i, v); -} - static inline void atomic_inc(atomic_t *v) { atomic_add_return(1, v); -- GitLab From 15e3f6d782fc6ff7e004b40642ad895b91ae78bf Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 26 Mar 2014 18:04:44 +0100 Subject: [PATCH 0294/5088] locking,arch,parisc: Fold atomic_ops OK, no LoC saved in this case because sub was defined in terms of add. Still do it because this also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Cc: Helge Deller Cc: James E.J. Bottomley Cc: Linus Torvalds Cc: Paul E. McKenney Cc: linux-parisc@vger.kernel.org Link: http://lkml.kernel.org/r/20140508135852.659342353@infradead.org Signed-off-by: Ingo Molnar --- arch/parisc/include/asm/atomic.h | 113 +++++++++++++++++++------------ 1 file changed, 69 insertions(+), 44 deletions(-) diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 0be2db2c7d44..219750bb4ae7 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -55,24 +55,7 @@ extern arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned; * are atomic, so a reader never sees inconsistent values. */ -/* It's possible to reduce all atomic operations to either - * __atomic_add_return, atomic_set and atomic_read (the latter - * is there only for consistency). - */ - -static __inline__ int __atomic_add_return(int i, atomic_t *v) -{ - int ret; - unsigned long flags; - _atomic_spin_lock_irqsave(v, flags); - - ret = (v->counter += i); - - _atomic_spin_unlock_irqrestore(v, flags); - return ret; -} - -static __inline__ void atomic_set(atomic_t *v, int i) +static __inline__ void atomic_set(atomic_t *v, int i) { unsigned long flags; _atomic_spin_lock_irqsave(v, flags); @@ -115,16 +98,43 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) return c; } +#define ATOMIC_OP(op, c_op) \ +static __inline__ void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + \ + _atomic_spin_lock_irqsave(v, flags); \ + v->counter c_op i; \ + _atomic_spin_unlock_irqrestore(v, flags); \ +} \ + +#define ATOMIC_OP_RETURN(op, c_op) \ +static __inline__ int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + int ret; \ + \ + _atomic_spin_lock_irqsave(v, flags); \ + ret = (v->counter c_op i); \ + _atomic_spin_unlock_irqrestore(v, flags); \ + \ + return ret; \ +} + +#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) + +ATOMIC_OPS(add, +=) +ATOMIC_OPS(sub, -=) + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP -#define atomic_add(i,v) ((void)(__atomic_add_return( (i),(v)))) -#define atomic_sub(i,v) ((void)(__atomic_add_return(-((int) (i)),(v)))) -#define atomic_inc(v) ((void)(__atomic_add_return( 1,(v)))) -#define atomic_dec(v) ((void)(__atomic_add_return( -1,(v)))) +#define atomic_inc(v) (atomic_add( 1,(v))) +#define atomic_dec(v) (atomic_add( -1,(v))) -#define atomic_add_return(i,v) (__atomic_add_return( (i),(v))) -#define atomic_sub_return(i,v) (__atomic_add_return(-(i),(v))) -#define atomic_inc_return(v) (__atomic_add_return( 1,(v))) -#define atomic_dec_return(v) (__atomic_add_return( -1,(v))) +#define atomic_inc_return(v) (atomic_add_return( 1,(v))) +#define atomic_dec_return(v) (atomic_add_return( -1,(v))) #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) @@ -148,18 +158,37 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) #define ATOMIC64_INIT(i) { (i) } -static __inline__ s64 -__atomic64_add_return(s64 i, atomic64_t *v) -{ - s64 ret; - unsigned long flags; - _atomic_spin_lock_irqsave(v, flags); +#define ATOMIC64_OP(op, c_op) \ +static __inline__ void atomic64_##op(s64 i, atomic64_t *v) \ +{ \ + unsigned long flags; \ + \ + _atomic_spin_lock_irqsave(v, flags); \ + v->counter c_op i; \ + _atomic_spin_unlock_irqrestore(v, flags); \ +} \ + +#define ATOMIC64_OP_RETURN(op, c_op) \ +static __inline__ s64 atomic64_##op##_return(s64 i, atomic64_t *v) \ +{ \ + unsigned long flags; \ + s64 ret; \ + \ + _atomic_spin_lock_irqsave(v, flags); \ + ret = (v->counter c_op i); \ + _atomic_spin_unlock_irqrestore(v, flags); \ + \ + return ret; \ +} - ret = (v->counter += i); +#define ATOMIC64_OPS(op, c_op) ATOMIC64_OP(op, c_op) ATOMIC64_OP_RETURN(op, c_op) - _atomic_spin_unlock_irqrestore(v, flags); - return ret; -} +ATOMIC64_OPS(add, +=) +ATOMIC64_OPS(sub, -=) + +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP static __inline__ void atomic64_set(atomic64_t *v, s64 i) @@ -178,15 +207,11 @@ atomic64_read(const atomic64_t *v) return (*(volatile long *)&(v)->counter); } -#define atomic64_add(i,v) ((void)(__atomic64_add_return( ((s64)(i)),(v)))) -#define atomic64_sub(i,v) ((void)(__atomic64_add_return(-((s64)(i)),(v)))) -#define atomic64_inc(v) ((void)(__atomic64_add_return( 1,(v)))) -#define atomic64_dec(v) ((void)(__atomic64_add_return( -1,(v)))) +#define atomic64_inc(v) (atomic64_add( 1,(v))) +#define atomic64_dec(v) (atomic64_add( -1,(v))) -#define atomic64_add_return(i,v) (__atomic64_add_return( ((s64)(i)),(v))) -#define atomic64_sub_return(i,v) (__atomic64_add_return(-((s64)(i)),(v))) -#define atomic64_inc_return(v) (__atomic64_add_return( 1,(v))) -#define atomic64_dec_return(v) (__atomic64_add_return( -1,(v))) +#define atomic64_inc_return(v) (atomic64_add_return( 1,(v))) +#define atomic64_dec_return(v) (atomic64_add_return( -1,(v))) #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) -- GitLab From af095dd60bdc52b11c186c3151e8e38d6faa094c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 26 Mar 2014 18:11:31 +0100 Subject: [PATCH 0295/5088] locking,arch,powerpc: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. Requires asm_op because PPC asm is weird :-) Signed-off-by: Peter Zijlstra Cc: Benjamin Herrenschmidt Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Paul Mackerras Cc: Mahesh Salgaonkar Cc: Paul Gortmaker Cc: linuxppc-dev@lists.ozlabs.org Link: http://lkml.kernel.org/r/20140508135852.713980957@infradead.org Signed-off-by: Ingo Molnar --- arch/powerpc/include/asm/atomic.h | 198 ++++++++++++------------------ 1 file changed, 77 insertions(+), 121 deletions(-) diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index 28992d012926..512d2782b043 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -26,76 +26,53 @@ static __inline__ void atomic_set(atomic_t *v, int i) __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); } -static __inline__ void atomic_add(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( -"1: lwarx %0,0,%3 # atomic_add\n\ - add %0,%2,%0\n" - PPC405_ERR77(0,%3) -" stwcx. %0,0,%3 \n\ - bne- 1b" - : "=&r" (t), "+m" (v->counter) - : "r" (a), "r" (&v->counter) - : "cc"); +#define ATOMIC_OP(op, asm_op) \ +static __inline__ void atomic_##op(int a, atomic_t *v) \ +{ \ + int t; \ + \ + __asm__ __volatile__( \ +"1: lwarx %0,0,%3 # atomic_" #op "\n" \ + #asm_op " %0,%2,%0\n" \ + PPC405_ERR77(0,%3) \ +" stwcx. %0,0,%3 \n" \ +" bne- 1b\n" \ + : "=&r" (t), "+m" (v->counter) \ + : "r" (a), "r" (&v->counter) \ + : "cc"); \ +} \ + +#define ATOMIC_OP_RETURN(op, asm_op) \ +static __inline__ int atomic_##op##_return(int a, atomic_t *v) \ +{ \ + int t; \ + \ + __asm__ __volatile__( \ + PPC_ATOMIC_ENTRY_BARRIER \ +"1: lwarx %0,0,%2 # atomic_" #op "_return\n" \ + #asm_op " %0,%1,%0\n" \ + PPC405_ERR77(0,%2) \ +" stwcx. %0,0,%2 \n" \ +" bne- 1b\n" \ + PPC_ATOMIC_EXIT_BARRIER \ + : "=&r" (t) \ + : "r" (a), "r" (&v->counter) \ + : "cc", "memory"); \ + \ + return t; \ } -static __inline__ int atomic_add_return(int a, atomic_t *v) -{ - int t; +#define ATOMIC_OPS(op, asm_op) ATOMIC_OP(op, asm_op) ATOMIC_OP_RETURN(op, asm_op) - __asm__ __volatile__( - PPC_ATOMIC_ENTRY_BARRIER -"1: lwarx %0,0,%2 # atomic_add_return\n\ - add %0,%1,%0\n" - PPC405_ERR77(0,%2) -" stwcx. %0,0,%2 \n\ - bne- 1b" - PPC_ATOMIC_EXIT_BARRIER - : "=&r" (t) - : "r" (a), "r" (&v->counter) - : "cc", "memory"); +ATOMIC_OPS(add, add) +ATOMIC_OPS(sub, subf) - return t; -} +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) -static __inline__ void atomic_sub(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( -"1: lwarx %0,0,%3 # atomic_sub\n\ - subf %0,%2,%0\n" - PPC405_ERR77(0,%3) -" stwcx. %0,0,%3 \n\ - bne- 1b" - : "=&r" (t), "+m" (v->counter) - : "r" (a), "r" (&v->counter) - : "cc"); -} - -static __inline__ int atomic_sub_return(int a, atomic_t *v) -{ - int t; - - __asm__ __volatile__( - PPC_ATOMIC_ENTRY_BARRIER -"1: lwarx %0,0,%2 # atomic_sub_return\n\ - subf %0,%1,%0\n" - PPC405_ERR77(0,%2) -" stwcx. %0,0,%2 \n\ - bne- 1b" - PPC_ATOMIC_EXIT_BARRIER - : "=&r" (t) - : "r" (a), "r" (&v->counter) - : "cc", "memory"); - - return t; -} - static __inline__ void atomic_inc(atomic_t *v) { int t; @@ -289,71 +266,50 @@ static __inline__ void atomic64_set(atomic64_t *v, long i) __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); } -static __inline__ void atomic64_add(long a, atomic64_t *v) -{ - long t; - - __asm__ __volatile__( -"1: ldarx %0,0,%3 # atomic64_add\n\ - add %0,%2,%0\n\ - stdcx. %0,0,%3 \n\ - bne- 1b" - : "=&r" (t), "+m" (v->counter) - : "r" (a), "r" (&v->counter) - : "cc"); +#define ATOMIC64_OP(op, asm_op) \ +static __inline__ void atomic64_##op(long a, atomic64_t *v) \ +{ \ + long t; \ + \ + __asm__ __volatile__( \ +"1: ldarx %0,0,%3 # atomic64_" #op "\n" \ + #asm_op " %0,%2,%0\n" \ +" stdcx. %0,0,%3 \n" \ +" bne- 1b\n" \ + : "=&r" (t), "+m" (v->counter) \ + : "r" (a), "r" (&v->counter) \ + : "cc"); \ } -static __inline__ long atomic64_add_return(long a, atomic64_t *v) -{ - long t; - - __asm__ __volatile__( - PPC_ATOMIC_ENTRY_BARRIER -"1: ldarx %0,0,%2 # atomic64_add_return\n\ - add %0,%1,%0\n\ - stdcx. %0,0,%2 \n\ - bne- 1b" - PPC_ATOMIC_EXIT_BARRIER - : "=&r" (t) - : "r" (a), "r" (&v->counter) - : "cc", "memory"); - - return t; +#define ATOMIC64_OP_RETURN(op, asm_op) \ +static __inline__ long atomic64_##op##_return(long a, atomic64_t *v) \ +{ \ + long t; \ + \ + __asm__ __volatile__( \ + PPC_ATOMIC_ENTRY_BARRIER \ +"1: ldarx %0,0,%2 # atomic64_" #op "_return\n" \ + #asm_op " %0,%1,%0\n" \ +" stdcx. %0,0,%2 \n" \ +" bne- 1b\n" \ + PPC_ATOMIC_EXIT_BARRIER \ + : "=&r" (t) \ + : "r" (a), "r" (&v->counter) \ + : "cc", "memory"); \ + \ + return t; \ } -#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) - -static __inline__ void atomic64_sub(long a, atomic64_t *v) -{ - long t; - - __asm__ __volatile__( -"1: ldarx %0,0,%3 # atomic64_sub\n\ - subf %0,%2,%0\n\ - stdcx. %0,0,%3 \n\ - bne- 1b" - : "=&r" (t), "+m" (v->counter) - : "r" (a), "r" (&v->counter) - : "cc"); -} +#define ATOMIC64_OPS(op, asm_op) ATOMIC64_OP(op, asm_op) ATOMIC64_OP_RETURN(op, asm_op) -static __inline__ long atomic64_sub_return(long a, atomic64_t *v) -{ - long t; +ATOMIC64_OPS(add, add) +ATOMIC64_OPS(sub, subf) - __asm__ __volatile__( - PPC_ATOMIC_ENTRY_BARRIER -"1: ldarx %0,0,%2 # atomic64_sub_return\n\ - subf %0,%1,%0\n\ - stdcx. %0,0,%2 \n\ - bne- 1b" - PPC_ATOMIC_EXIT_BARRIER - : "=&r" (t) - : "r" (a), "r" (&v->counter) - : "cc", "memory"); +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP - return t; -} +#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) static __inline__ void atomic64_inc(atomic64_t *v) { -- GitLab From c6470150dff9aff682063890c9b8eac71b695def Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 26 Mar 2014 18:12:45 +0100 Subject: [PATCH 0296/5088] locking,arch,sh: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Cc: linux-sh@vger.kernel.org Link: http://lkml.kernel.org/r/20140508135852.770036493@infradead.org Signed-off-by: Ingo Molnar --- arch/sh/include/asm/atomic-grb.h | 119 +++++++++++------------------- arch/sh/include/asm/atomic-irq.h | 62 +++++++--------- arch/sh/include/asm/atomic-llsc.h | 101 ++++++++++--------------- 3 files changed, 112 insertions(+), 170 deletions(-) diff --git a/arch/sh/include/asm/atomic-grb.h b/arch/sh/include/asm/atomic-grb.h index a273c88578fc..97a5fda83450 100644 --- a/arch/sh/include/asm/atomic-grb.h +++ b/arch/sh/include/asm/atomic-grb.h @@ -1,85 +1,56 @@ #ifndef __ASM_SH_ATOMIC_GRB_H #define __ASM_SH_ATOMIC_GRB_H -static inline void atomic_add(int i, 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 */ - " add %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" (i) - : "memory" , "r0", "r1"); -} - -static inline void atomic_sub(int i, 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 */ - " sub %2, %0 \n\t" /* sub */ - " mov.l %0, @%1 \n\t" /* store new value */ - "1: mov r1, r15 \n\t" /* LOGOUT */ - : "=&r" (tmp), - "+r" (v) - : "r" (i) - : "memory" , "r0", "r1"); -} - -static inline int atomic_add_return(int i, atomic_t *v) -{ - int tmp; +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, 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 */ \ + " " #op " %2, %0 \n\t" /* $op */ \ + " mov.l %0, @%1 \n\t" /* store new value */ \ + "1: mov r1, r15 \n\t" /* LOGOUT */ \ + : "=&r" (tmp), \ + "+r" (v) \ + : "r" (i) \ + : "memory" , "r0", "r1"); \ +} \ - __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 */ - " add %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" (i) - : "memory" , "r0", "r1"); - - return tmp; +#define ATOMIC_OP_RETURN(op) \ +static inline int atomic_##op##_return(int i, 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 */ \ + " " #op " %2, %0 \n\t" /* $op */ \ + " mov.l %0, @%1 \n\t" /* store new value */ \ + "1: mov r1, r15 \n\t" /* LOGOUT */ \ + : "=&r" (tmp), \ + "+r" (v) \ + : "r" (i) \ + : "memory" , "r0", "r1"); \ + \ + return tmp; \ } -static inline int atomic_sub_return(int i, atomic_t *v) -{ - int tmp; +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) - __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 */ - " sub %2, %0 \n\t" /* sub */ - " mov.l %0, @%1 \n\t" /* store new value */ - "1: mov r1, r15 \n\t" /* LOGOUT */ - : "=&r" (tmp), - "+r" (v) - : "r" (i) - : "memory", "r0", "r1"); +ATOMIC_OPS(add) +ATOMIC_OPS(sub) - return tmp; -} +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) { diff --git a/arch/sh/include/asm/atomic-irq.h b/arch/sh/include/asm/atomic-irq.h index 9f7c56609e53..61d107523f06 100644 --- a/arch/sh/include/asm/atomic-irq.h +++ b/arch/sh/include/asm/atomic-irq.h @@ -8,49 +8,39 @@ * forward to code at the end of this object's .text section, then * branch back to restart the operation. */ -static inline void atomic_add(int i, atomic_t *v) -{ - unsigned long flags; - - raw_local_irq_save(flags); - v->counter += i; - raw_local_irq_restore(flags); -} -static inline void atomic_sub(int i, atomic_t *v) -{ - unsigned long flags; - - raw_local_irq_save(flags); - v->counter -= i; - raw_local_irq_restore(flags); +#define ATOMIC_OP(op, c_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ } -static inline int atomic_add_return(int i, atomic_t *v) -{ - unsigned long temp, flags; - - raw_local_irq_save(flags); - temp = v->counter; - temp += i; - v->counter = temp; - raw_local_irq_restore(flags); - - return temp; +#define ATOMIC_OP_RETURN(op, c_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long temp, flags; \ + \ + raw_local_irq_save(flags); \ + temp = v->counter; \ + temp c_op i; \ + v->counter = temp; \ + raw_local_irq_restore(flags); \ + \ + return temp; \ } -static inline int atomic_sub_return(int i, atomic_t *v) -{ - unsigned long temp, flags; +#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) - raw_local_irq_save(flags); - temp = v->counter; - temp -= i; - v->counter = temp; - raw_local_irq_restore(flags); +ATOMIC_OPS(add, +=) +ATOMIC_OPS(sub, -=) - return temp; -} +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) { diff --git a/arch/sh/include/asm/atomic-llsc.h b/arch/sh/include/asm/atomic-llsc.h index 4b00b78e3f4f..8575dccb9ef7 100644 --- a/arch/sh/include/asm/atomic-llsc.h +++ b/arch/sh/include/asm/atomic-llsc.h @@ -1,39 +1,6 @@ #ifndef __ASM_SH_ATOMIC_LLSC_H #define __ASM_SH_ATOMIC_LLSC_H -/* - * To get proper branch prediction for the main line, we must branch - * forward to code at the end of this object's .text section, then - * branch back to restart the operation. - */ -static inline void atomic_add(int i, atomic_t *v) -{ - unsigned long tmp; - - __asm__ __volatile__ ( -"1: movli.l @%2, %0 ! atomic_add \n" -" add %1, %0 \n" -" movco.l %0, @%2 \n" -" bf 1b \n" - : "=&z" (tmp) - : "r" (i), "r" (&v->counter) - : "t"); -} - -static inline void atomic_sub(int i, atomic_t *v) -{ - unsigned long tmp; - - __asm__ __volatile__ ( -"1: movli.l @%2, %0 ! atomic_sub \n" -" sub %1, %0 \n" -" movco.l %0, @%2 \n" -" bf 1b \n" - : "=&z" (tmp) - : "r" (i), "r" (&v->counter) - : "t"); -} - /* * SH-4A note: * @@ -42,39 +9,53 @@ static inline void atomic_sub(int i, atomic_t *v) * encoding, so the retval is automatically set without having to * do any special work. */ -static inline int atomic_add_return(int i, atomic_t *v) -{ - unsigned long temp; +/* + * To get proper branch prediction for the main line, we must branch + * forward to code at the end of this object's .text section, then + * branch back to restart the operation. + */ - __asm__ __volatile__ ( -"1: movli.l @%2, %0 ! atomic_add_return \n" -" add %1, %0 \n" -" movco.l %0, @%2 \n" -" bf 1b \n" -" synco \n" - : "=&z" (temp) - : "r" (i), "r" (&v->counter) - : "t"); +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long tmp; \ + \ + __asm__ __volatile__ ( \ +"1: movli.l @%2, %0 ! atomic_" #op "\n" \ +" " #op " %1, %0 \n" \ +" movco.l %0, @%2 \n" \ +" bf 1b \n" \ + : "=&z" (tmp) \ + : "r" (i), "r" (&v->counter) \ + : "t"); \ +} - return temp; +#define ATOMIC_OP_RETURN(op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long temp; \ + \ + __asm__ __volatile__ ( \ +"1: movli.l @%2, %0 ! atomic_" #op "_return \n" \ +" " #op " %1, %0 \n" \ +" movco.l %0, @%2 \n" \ +" bf 1b \n" \ +" synco \n" \ + : "=&z" (temp) \ + : "r" (i), "r" (&v->counter) \ + : "t"); \ + \ + return temp; \ } -static inline int atomic_sub_return(int i, atomic_t *v) -{ - unsigned long temp; +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) - __asm__ __volatile__ ( -"1: movli.l @%2, %0 ! atomic_sub_return \n" -" sub %1, %0 \n" -" movco.l %0, @%2 \n" -" bf 1b \n" -" synco \n" - : "=&z" (temp) - : "r" (i), "r" (&v->counter) - : "t"); +ATOMIC_OPS(add) +ATOMIC_OPS(sub) - return temp; -} +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) { -- GitLab From 4f3316c2b5fe2062c26c9b66915b5a5c80c60a5c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 26 Mar 2014 18:29:28 +0100 Subject: [PATCH 0297/5088] locking,arch,sparc: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Acked-by: David S. Miller Cc: Bjorn Helgaas Cc: Kirill Tkhai Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Sam Ravnborg Cc: sparclinux@vger.kernel.org Link: http://lkml.kernel.org/r/20140508135852.825281379@infradead.org Signed-off-by: Ingo Molnar --- arch/sparc/include/asm/atomic_32.h | 17 ++- arch/sparc/include/asm/atomic_64.h | 45 ++++---- arch/sparc/kernel/smp_64.c | 2 +- arch/sparc/lib/atomic32.c | 29 ++--- arch/sparc/lib/atomic_64.S | 163 ++++++++++++----------------- arch/sparc/lib/ksyms.c | 25 +++-- 6 files changed, 133 insertions(+), 148 deletions(-) diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index 7aed2be45b44..7b024f02a7ce 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -20,7 +20,7 @@ #define ATOMIC_INIT(i) { (i) } -int __atomic_add_return(int, atomic_t *); +int atomic_add_return(int, atomic_t *); int atomic_cmpxchg(atomic_t *, int, int); #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) int __atomic_add_unless(atomic_t *, int, int); @@ -28,15 +28,14 @@ void atomic_set(atomic_t *, int); #define atomic_read(v) (*(volatile int *)&(v)->counter) -#define atomic_add(i, v) ((void)__atomic_add_return( (int)(i), (v))) -#define atomic_sub(i, v) ((void)__atomic_add_return(-(int)(i), (v))) -#define atomic_inc(v) ((void)__atomic_add_return( 1, (v))) -#define atomic_dec(v) ((void)__atomic_add_return( -1, (v))) +#define atomic_add(i, v) ((void)atomic_add_return( (int)(i), (v))) +#define atomic_sub(i, v) ((void)atomic_add_return(-(int)(i), (v))) +#define atomic_inc(v) ((void)atomic_add_return( 1, (v))) +#define atomic_dec(v) ((void)atomic_add_return( -1, (v))) -#define atomic_add_return(i, v) (__atomic_add_return( (int)(i), (v))) -#define atomic_sub_return(i, v) (__atomic_add_return(-(int)(i), (v))) -#define atomic_inc_return(v) (__atomic_add_return( 1, (v))) -#define atomic_dec_return(v) (__atomic_add_return( -1, (v))) +#define atomic_sub_return(i, v) (atomic_add_return(-(int)(i), (v))) +#define atomic_inc_return(v) (atomic_add_return( 1, (v))) +#define atomic_dec_return(v) (atomic_add_return( -1, (v))) #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index bb894c8bec56..7e4ca1e73cd9 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -20,27 +20,28 @@ #define atomic_set(v, i) (((v)->counter) = i) #define atomic64_set(v, i) (((v)->counter) = i) -void atomic_add(int, atomic_t *); -void atomic64_add(long, atomic64_t *); -void atomic_sub(int, atomic_t *); -void atomic64_sub(long, atomic64_t *); +#define ATOMIC_OP(op) \ +void atomic_##op(int, atomic_t *); \ +void atomic64_##op(long, atomic64_t *); -int atomic_add_ret(int, atomic_t *); -long atomic64_add_ret(long, atomic64_t *); -int atomic_sub_ret(int, atomic_t *); -long atomic64_sub_ret(long, atomic64_t *); +#define ATOMIC_OP_RETURN(op) \ +int atomic_##op##_return(int, atomic_t *); \ +long atomic64_##op##_return(long, atomic64_t *); -#define atomic_dec_return(v) atomic_sub_ret(1, v) -#define atomic64_dec_return(v) atomic64_sub_ret(1, v) +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) -#define atomic_inc_return(v) atomic_add_ret(1, v) -#define atomic64_inc_return(v) atomic64_add_ret(1, v) +ATOMIC_OPS(add) +ATOMIC_OPS(sub) -#define atomic_sub_return(i, v) atomic_sub_ret(i, v) -#define atomic64_sub_return(i, v) atomic64_sub_ret(i, v) +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP -#define atomic_add_return(i, v) atomic_add_ret(i, v) -#define atomic64_add_return(i, v) atomic64_add_ret(i, v) +#define atomic_dec_return(v) atomic_sub_return(1, v) +#define atomic64_dec_return(v) atomic64_sub_return(1, v) + +#define atomic_inc_return(v) atomic_add_return(1, v) +#define atomic64_inc_return(v) atomic64_add_return(1, v) /* * atomic_inc_and_test - increment and test @@ -53,11 +54,11 @@ long atomic64_sub_ret(long, atomic64_t *); #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) -#define atomic_sub_and_test(i, v) (atomic_sub_ret(i, v) == 0) -#define atomic64_sub_and_test(i, v) (atomic64_sub_ret(i, v) == 0) +#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) +#define atomic64_sub_and_test(i, v) (atomic64_sub_return(i, v) == 0) -#define atomic_dec_and_test(v) (atomic_sub_ret(1, v) == 0) -#define atomic64_dec_and_test(v) (atomic64_sub_ret(1, v) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) +#define atomic64_dec_and_test(v) (atomic64_sub_return(1, v) == 0) #define atomic_inc(v) atomic_add(1, v) #define atomic64_inc(v) atomic64_add(1, v) @@ -65,8 +66,8 @@ long atomic64_sub_ret(long, atomic64_t *); #define atomic_dec(v) atomic_sub(1, v) #define atomic64_dec(v) atomic64_sub(1, v) -#define atomic_add_negative(i, v) (atomic_add_ret(i, v) < 0) -#define atomic64_add_negative(i, v) (atomic64_add_ret(i, v) < 0) +#define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0) +#define atomic64_add_negative(i, v) (atomic64_add_return(i, v) < 0) #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 41aa2478f3ca..32dab009915f 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -1138,7 +1138,7 @@ static unsigned long penguins_are_doing_time; void smp_capture(void) { - int result = atomic_add_ret(1, &smp_capture_depth); + int result = atomic_add_return(1, &smp_capture_depth); if (result == 1) { int ncpus = num_online_cpus(); diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c index 1d32b54089aa..a7c418ac26af 100644 --- a/arch/sparc/lib/atomic32.c +++ b/arch/sparc/lib/atomic32.c @@ -27,18 +27,23 @@ static DEFINE_SPINLOCK(dummy); #endif /* SMP */ -int __atomic_add_return(int i, atomic_t *v) -{ - int ret; - unsigned long flags; - spin_lock_irqsave(ATOMIC_HASH(v), flags); - - ret = (v->counter += i); - - spin_unlock_irqrestore(ATOMIC_HASH(v), flags); - return ret; -} -EXPORT_SYMBOL(__atomic_add_return); +#define ATOMIC_OP(op, cop) \ +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); \ + \ + spin_unlock_irqrestore(ATOMIC_HASH(v), flags); \ + return ret; \ +} \ +EXPORT_SYMBOL(atomic_##op##_return); + +ATOMIC_OP(add, +=) + +#undef ATOMIC_OP int atomic_cmpxchg(atomic_t *v, int old, int new) { diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index 85c233d0a340..96d70b4dbe77 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S @@ -14,109 +14,80 @@ * memory barriers, and a second which returns * a value and does the barriers. */ -ENTRY(atomic_add) /* %o0 = increment, %o1 = atomic_ptr */ - BACKOFF_SETUP(%o2) -1: lduw [%o1], %g1 - add %g1, %o0, %g7 - cas [%o1], %g1, %g7 - cmp %g1, %g7 - bne,pn %icc, BACKOFF_LABEL(2f, 1b) - nop - retl - nop -2: BACKOFF_SPIN(%o2, %o3, 1b) -ENDPROC(atomic_add) -ENTRY(atomic_sub) /* %o0 = decrement, %o1 = atomic_ptr */ - BACKOFF_SETUP(%o2) -1: lduw [%o1], %g1 - sub %g1, %o0, %g7 - cas [%o1], %g1, %g7 - cmp %g1, %g7 - bne,pn %icc, BACKOFF_LABEL(2f, 1b) - nop - retl - nop -2: BACKOFF_SPIN(%o2, %o3, 1b) -ENDPROC(atomic_sub) +#define ATOMIC_OP(op) \ +ENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ + BACKOFF_SETUP(%o2); \ +1: lduw [%o1], %g1; \ + op %g1, %o0, %g7; \ + cas [%o1], %g1, %g7; \ + cmp %g1, %g7; \ + bne,pn %icc, BACKOFF_LABEL(2f, 1b); \ + nop; \ + retl; \ + nop; \ +2: BACKOFF_SPIN(%o2, %o3, 1b); \ +ENDPROC(atomic_##op); \ -ENTRY(atomic_add_ret) /* %o0 = increment, %o1 = atomic_ptr */ - BACKOFF_SETUP(%o2) -1: lduw [%o1], %g1 - add %g1, %o0, %g7 - cas [%o1], %g1, %g7 - cmp %g1, %g7 - bne,pn %icc, BACKOFF_LABEL(2f, 1b) - add %g1, %o0, %g1 - retl - sra %g1, 0, %o0 -2: BACKOFF_SPIN(%o2, %o3, 1b) -ENDPROC(atomic_add_ret) +#define ATOMIC_OP_RETURN(op) \ +ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ + BACKOFF_SETUP(%o2); \ +1: lduw [%o1], %g1; \ + op %g1, %o0, %g7; \ + cas [%o1], %g1, %g7; \ + cmp %g1, %g7; \ + bne,pn %icc, BACKOFF_LABEL(2f, 1b); \ + add %g1, %o0, %g1; \ + retl; \ + sra %g1, 0, %o0; \ +2: BACKOFF_SPIN(%o2, %o3, 1b); \ +ENDPROC(atomic_##op##_return); -ENTRY(atomic_sub_ret) /* %o0 = decrement, %o1 = atomic_ptr */ - BACKOFF_SETUP(%o2) -1: lduw [%o1], %g1 - sub %g1, %o0, %g7 - cas [%o1], %g1, %g7 - cmp %g1, %g7 - bne,pn %icc, BACKOFF_LABEL(2f, 1b) - sub %g1, %o0, %g1 - retl - sra %g1, 0, %o0 -2: BACKOFF_SPIN(%o2, %o3, 1b) -ENDPROC(atomic_sub_ret) +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) -ENTRY(atomic64_add) /* %o0 = increment, %o1 = atomic_ptr */ - BACKOFF_SETUP(%o2) -1: ldx [%o1], %g1 - add %g1, %o0, %g7 - casx [%o1], %g1, %g7 - cmp %g1, %g7 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) - nop - retl - nop -2: BACKOFF_SPIN(%o2, %o3, 1b) -ENDPROC(atomic64_add) +ATOMIC_OPS(add) +ATOMIC_OPS(sub) -ENTRY(atomic64_sub) /* %o0 = decrement, %o1 = atomic_ptr */ - BACKOFF_SETUP(%o2) -1: ldx [%o1], %g1 - sub %g1, %o0, %g7 - casx [%o1], %g1, %g7 - cmp %g1, %g7 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) - nop - retl - nop -2: BACKOFF_SPIN(%o2, %o3, 1b) -ENDPROC(atomic64_sub) +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP -ENTRY(atomic64_add_ret) /* %o0 = increment, %o1 = atomic_ptr */ - BACKOFF_SETUP(%o2) -1: ldx [%o1], %g1 - add %g1, %o0, %g7 - casx [%o1], %g1, %g7 - cmp %g1, %g7 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) - nop - retl - add %g1, %o0, %o0 -2: BACKOFF_SPIN(%o2, %o3, 1b) -ENDPROC(atomic64_add_ret) +#define ATOMIC64_OP(op) \ +ENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ + BACKOFF_SETUP(%o2); \ +1: ldx [%o1], %g1; \ + op %g1, %o0, %g7; \ + casx [%o1], %g1, %g7; \ + cmp %g1, %g7; \ + bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \ + nop; \ + retl; \ + nop; \ +2: BACKOFF_SPIN(%o2, %o3, 1b); \ +ENDPROC(atomic64_##op); \ -ENTRY(atomic64_sub_ret) /* %o0 = decrement, %o1 = atomic_ptr */ - BACKOFF_SETUP(%o2) -1: ldx [%o1], %g1 - sub %g1, %o0, %g7 - casx [%o1], %g1, %g7 - cmp %g1, %g7 - bne,pn %xcc, BACKOFF_LABEL(2f, 1b) - nop - retl - sub %g1, %o0, %o0 -2: BACKOFF_SPIN(%o2, %o3, 1b) -ENDPROC(atomic64_sub_ret) +#define ATOMIC64_OP_RETURN(op) \ +ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ + BACKOFF_SETUP(%o2); \ +1: ldx [%o1], %g1; \ + op %g1, %o0, %g7; \ + casx [%o1], %g1, %g7; \ + cmp %g1, %g7; \ + bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \ + nop; \ + retl; \ + add %g1, %o0, %o0; \ +2: BACKOFF_SPIN(%o2, %o3, 1b); \ +ENDPROC(atomic64_##op##_return); + +#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) + +ATOMIC64_OPS(add) +ATOMIC64_OPS(sub) + +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP ENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */ BACKOFF_SETUP(%o2) diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c index 323335b9cd2b..1d649a95660c 100644 --- a/arch/sparc/lib/ksyms.c +++ b/arch/sparc/lib/ksyms.c @@ -99,14 +99,23 @@ EXPORT_SYMBOL(___copy_in_user); EXPORT_SYMBOL(__clear_user); /* Atomic counter implementation. */ -EXPORT_SYMBOL(atomic_add); -EXPORT_SYMBOL(atomic_add_ret); -EXPORT_SYMBOL(atomic_sub); -EXPORT_SYMBOL(atomic_sub_ret); -EXPORT_SYMBOL(atomic64_add); -EXPORT_SYMBOL(atomic64_add_ret); -EXPORT_SYMBOL(atomic64_sub); -EXPORT_SYMBOL(atomic64_sub_ret); +#define ATOMIC_OP(op) \ +EXPORT_SYMBOL(atomic_##op); \ +EXPORT_SYMBOL(atomic64_##op); + +#define ATOMIC_OP_RETURN(op) \ +EXPORT_SYMBOL(atomic_##op##_return); \ +EXPORT_SYMBOL(atomic64_##op##_return); + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) + +ATOMIC_OPS(add) +ATOMIC_OPS(sub) + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + EXPORT_SYMBOL(atomic64_dec_if_positive); /* Atomic bit operations. */ -- GitLab From d4608dd5b4ec13855680b89f719d8d4b2da92411 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 26 Mar 2014 18:31:12 +0100 Subject: [PATCH 0298/5088] locking,arch,xtensa: Fold atomic_ops Many of the atomic op implementations are the same except for one instruction; fold the lot into a few CPP macros and reduce LoC. This also prepares for easy addition of new ops. Signed-off-by: Peter Zijlstra Cc: Chris Zankel Cc: Linus Torvalds Cc: Max Filippov Cc: Geert Uytterhoeven Cc: Paul E. McKenney Cc: linux-xtensa@linux-xtensa.org Link: http://lkml.kernel.org/r/20140508135852.879575796@infradead.org Signed-off-by: Ingo Molnar --- arch/xtensa/include/asm/atomic.h | 233 +++++++++++-------------------- 1 file changed, 82 insertions(+), 151 deletions(-) diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index e5103b47a8ce..626676660b80 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -58,165 +58,96 @@ */ #define atomic_set(v,i) ((v)->counter = (i)) -/** - * atomic_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v. - */ -static inline void atomic_add(int i, atomic_t * v) -{ #if XCHAL_HAVE_S32C1I - unsigned long tmp; - int result; - - __asm__ __volatile__( - "1: l32i %1, %3, 0\n" - " wsr %1, scompare1\n" - " add %0, %1, %2\n" - " s32c1i %0, %3, 0\n" - " bne %0, %1, 1b\n" - : "=&a" (result), "=&a" (tmp) - : "a" (i), "a" (v) - : "memory" - ); -#else - unsigned int vval; - - __asm__ __volatile__( - " rsil a15, "__stringify(LOCKLEVEL)"\n" - " l32i %0, %2, 0\n" - " add %0, %0, %1\n" - " s32i %0, %2, 0\n" - " wsr a15, ps\n" - " rsync\n" - : "=&a" (vval) - : "a" (i), "a" (v) - : "a15", "memory" - ); -#endif -} - -/** - * atomic_sub - subtract the atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v. - */ -static inline void atomic_sub(int i, atomic_t *v) -{ -#if XCHAL_HAVE_S32C1I - unsigned long tmp; - int result; - - __asm__ __volatile__( - "1: l32i %1, %3, 0\n" - " wsr %1, scompare1\n" - " sub %0, %1, %2\n" - " s32c1i %0, %3, 0\n" - " bne %0, %1, 1b\n" - : "=&a" (result), "=&a" (tmp) - : "a" (i), "a" (v) - : "memory" - ); -#else - unsigned int vval; - - __asm__ __volatile__( - " rsil a15, "__stringify(LOCKLEVEL)"\n" - " l32i %0, %2, 0\n" - " sub %0, %0, %1\n" - " s32i %0, %2, 0\n" - " wsr a15, ps\n" - " rsync\n" - : "=&a" (vval) - : "a" (i), "a" (v) - : "a15", "memory" - ); -#endif +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, atomic_t * v) \ +{ \ + unsigned long tmp; \ + int result; \ + \ + __asm__ __volatile__( \ + "1: l32i %1, %3, 0\n" \ + " wsr %1, scompare1\n" \ + " " #op " %0, %1, %2\n" \ + " s32c1i %0, %3, 0\n" \ + " bne %0, %1, 1b\n" \ + : "=&a" (result), "=&a" (tmp) \ + : "a" (i), "a" (v) \ + : "memory" \ + ); \ +} \ + +#define ATOMIC_OP_RETURN(op) \ +static inline int atomic_##op##_return(int i, atomic_t * v) \ +{ \ + unsigned long tmp; \ + int result; \ + \ + __asm__ __volatile__( \ + "1: l32i %1, %3, 0\n" \ + " wsr %1, scompare1\n" \ + " " #op " %0, %1, %2\n" \ + " s32c1i %0, %3, 0\n" \ + " bne %0, %1, 1b\n" \ + " " #op " %0, %0, %2\n" \ + : "=&a" (result), "=&a" (tmp) \ + : "a" (i), "a" (v) \ + : "memory" \ + ); \ + \ + return result; \ } -/* - * We use atomic_{add|sub}_return to define other functions. - */ - -static inline int atomic_add_return(int i, atomic_t * v) -{ -#if XCHAL_HAVE_S32C1I - unsigned long tmp; - int result; - - __asm__ __volatile__( - "1: l32i %1, %3, 0\n" - " wsr %1, scompare1\n" - " add %0, %1, %2\n" - " s32c1i %0, %3, 0\n" - " bne %0, %1, 1b\n" - " add %0, %0, %2\n" - : "=&a" (result), "=&a" (tmp) - : "a" (i), "a" (v) - : "memory" - ); - - return result; -#else - unsigned int vval; - - __asm__ __volatile__( - " rsil a15,"__stringify(LOCKLEVEL)"\n" - " l32i %0, %2, 0\n" - " add %0, %0, %1\n" - " s32i %0, %2, 0\n" - " wsr a15, ps\n" - " rsync\n" - : "=&a" (vval) - : "a" (i), "a" (v) - : "a15", "memory" - ); - - return vval; -#endif +#else /* XCHAL_HAVE_S32C1I */ + +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, atomic_t * v) \ +{ \ + unsigned int vval; \ + \ + __asm__ __volatile__( \ + " rsil a15, "__stringify(LOCKLEVEL)"\n"\ + " l32i %0, %2, 0\n" \ + " " #op " %0, %0, %1\n" \ + " s32i %0, %2, 0\n" \ + " wsr a15, ps\n" \ + " rsync\n" \ + : "=&a" (vval) \ + : "a" (i), "a" (v) \ + : "a15", "memory" \ + ); \ +} \ + +#define ATOMIC_OP_RETURN(op) \ +static inline int atomic_##op##_return(int i, atomic_t * v) \ +{ \ + unsigned int vval; \ + \ + __asm__ __volatile__( \ + " rsil a15,"__stringify(LOCKLEVEL)"\n" \ + " l32i %0, %2, 0\n" \ + " " #op " %0, %0, %1\n" \ + " s32i %0, %2, 0\n" \ + " wsr a15, ps\n" \ + " rsync\n" \ + : "=&a" (vval) \ + : "a" (i), "a" (v) \ + : "a15", "memory" \ + ); \ + \ + return vval; \ } -static inline int atomic_sub_return(int i, atomic_t * v) -{ -#if XCHAL_HAVE_S32C1I - unsigned long tmp; - int result; +#endif /* XCHAL_HAVE_S32C1I */ - __asm__ __volatile__( - "1: l32i %1, %3, 0\n" - " wsr %1, scompare1\n" - " sub %0, %1, %2\n" - " s32c1i %0, %3, 0\n" - " bne %0, %1, 1b\n" - " sub %0, %0, %2\n" - : "=&a" (result), "=&a" (tmp) - : "a" (i), "a" (v) - : "memory" - ); +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) - return result; -#else - unsigned int vval; - - __asm__ __volatile__( - " rsil a15,"__stringify(LOCKLEVEL)"\n" - " l32i %0, %2, 0\n" - " sub %0, %0, %1\n" - " s32i %0, %2, 0\n" - " wsr a15, ps\n" - " rsync\n" - : "=&a" (vval) - : "a" (i), "a" (v) - : "a15", "memory" - ); +ATOMIC_OPS(add) +ATOMIC_OPS(sub) - return vval; -#endif -} +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP /** * atomic_sub_and_test - subtract value from variable and test result -- GitLab From 560cb12a4080a48b84da8b96878cafbd193c4d64 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 16:12:30 +0200 Subject: [PATCH 0299/5088] locking,arch: Rewrite generic atomic support Rewrite generic atomic support to only require cmpxchg(), generate all other primitives from that. Furthermore reduce the endless repetition for all these primitives to a few CPP macros. This way we get more for less lines. Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20140508135852.940119622@infradead.org Cc: Arnd Bergmann Cc: David Howells Cc: Paul E. McKenney Cc: David S. Miller Cc: Linus Torvalds Cc: linux-arch@vger.kernel.org Signed-off-by: Ingo Molnar --- include/asm-generic/atomic.h | 192 ++++++++++++++++----------------- include/asm-generic/atomic64.h | 20 +++- lib/atomic64.c | 83 +++++++------- 3 files changed, 148 insertions(+), 147 deletions(-) diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index 9c79e7603459..56d4d36e1531 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -18,14 +18,100 @@ #include #include +/* + * atomic_$op() - $op integer to atomic variable + * @i: integer value to $op + * @v: pointer to the atomic variable + * + * Atomically $ops @i to @v. Does not strictly guarantee a memory-barrier, use + * smp_mb__{before,after}_atomic(). + */ + +/* + * atomic_$op_return() - $op interer to atomic variable and returns the result + * @i: integer value to $op + * @v: pointer to the atomic variable + * + * Atomically $ops @i to @v. Does imply a full memory barrier. + */ + #ifdef CONFIG_SMP -/* Force people to define core atomics */ -# if !defined(atomic_add_return) || !defined(atomic_sub_return) || \ - !defined(atomic_clear_mask) || !defined(atomic_set_mask) -# error "SMP requires a little arch-specific magic" -# endif + +/* we can build all atomic primitives from cmpxchg */ + +#define ATOMIC_OP(op, c_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + int c, old; \ + \ + c = v->counter; \ + while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ + c = old; \ +} + +#define ATOMIC_OP_RETURN(op, c_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + int c, old; \ + \ + c = v->counter; \ + while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ + c = old; \ + \ + return c c_op i; \ +} + +#else + +#include + +#define ATOMIC_OP(op, c_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + v->counter = v->counter c_op i; \ + raw_local_irq_restore(flags); \ +} + +#define ATOMIC_OP_RETURN(op, c_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + int ret; \ + \ + raw_local_irq_save(flags); \ + ret = (v->counter = v->counter c_op i); \ + raw_local_irq_restore(flags); \ + \ + return ret; \ +} + +#endif /* CONFIG_SMP */ + +#ifndef atomic_add_return +ATOMIC_OP_RETURN(add, +) +#endif + +#ifndef atomic_sub_return +ATOMIC_OP_RETURN(sub, -) +#endif + +#ifndef atomic_clear_mask +ATOMIC_OP(and, &) +#define atomic_clear_mask(i, v) atomic_and(~(i), (v)) #endif +#ifndef atomic_set_mask +#define CONFIG_ARCH_HAS_ATOMIC_OR +ATOMIC_OP(or, |) +#define atomic_set_mask(i, v) atomic_or((i), (v)) +#endif + +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + /* * Atomic operations that C can't guarantee us. Useful for * resource counting etc.. @@ -33,8 +119,6 @@ #define ATOMIC_INIT(i) { (i) } -#ifdef __KERNEL__ - /** * atomic_read - read atomic variable * @v: pointer of type atomic_t @@ -56,52 +140,6 @@ #include -/** - * atomic_add_return - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v and returns the result - */ -#ifndef atomic_add_return -static inline int atomic_add_return(int i, atomic_t *v) -{ - unsigned long flags; - int temp; - - raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ - temp = v->counter; - temp += i; - v->counter = temp; - raw_local_irq_restore(flags); - - return temp; -} -#endif - -/** - * atomic_sub_return - subtract integer from atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v and returns the result - */ -#ifndef atomic_sub_return -static inline int atomic_sub_return(int i, atomic_t *v) -{ - unsigned long flags; - int temp; - - raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ - temp = v->counter; - temp -= i; - v->counter = temp; - raw_local_irq_restore(flags); - - return temp; -} -#endif - static inline int atomic_add_negative(int i, atomic_t *v) { return atomic_add_return(i, v) < 0; @@ -139,49 +177,11 @@ static inline void atomic_dec(atomic_t *v) 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; -} - -/** - * atomic_clear_mask - Atomically clear bits in atomic variable - * @mask: Mask of the bits to be cleared - * @v: pointer of type atomic_t - * - * Atomically clears the bits set in @mask from @v - */ -#ifndef atomic_clear_mask -static inline void atomic_clear_mask(unsigned long mask, atomic_t *v) -{ - unsigned long flags; - - mask = ~mask; - raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ - v->counter &= mask; - raw_local_irq_restore(flags); + int c, old; + c = atomic_read(v); + while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) + c = old; + return c; } -#endif - -/** - * atomic_set_mask - Atomically set bits in atomic variable - * @mask: Mask of the bits to be set - * @v: pointer of type atomic_t - * - * Atomically sets the bits set in @mask in @v - */ -#ifndef atomic_set_mask -static inline void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - unsigned long flags; - - raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ - v->counter |= mask; - raw_local_irq_restore(flags); -} -#endif -#endif /* __KERNEL__ */ #endif /* __ASM_GENERIC_ATOMIC_H */ diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h index b18ce4f9ee3d..30ad9c86cebb 100644 --- a/include/asm-generic/atomic64.h +++ b/include/asm-generic/atomic64.h @@ -20,10 +20,22 @@ typedef struct { extern long long atomic64_read(const atomic64_t *v); extern void atomic64_set(atomic64_t *v, long long i); -extern void atomic64_add(long long a, atomic64_t *v); -extern long long atomic64_add_return(long long a, atomic64_t *v); -extern void atomic64_sub(long long a, atomic64_t *v); -extern long long atomic64_sub_return(long long a, atomic64_t *v); + +#define ATOMIC64_OP(op) \ +extern void atomic64_##op(long long a, atomic64_t *v); + +#define ATOMIC64_OP_RETURN(op) \ +extern long long atomic64_##op##_return(long long a, atomic64_t *v); + +#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) + +ATOMIC64_OPS(add) +ATOMIC64_OPS(sub) + +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP + extern long long atomic64_dec_if_positive(atomic64_t *v); extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n); extern long long atomic64_xchg(atomic64_t *v, long long new); diff --git a/lib/atomic64.c b/lib/atomic64.c index 08a4f068e61e..1298c05ef528 100644 --- a/lib/atomic64.c +++ b/lib/atomic64.c @@ -70,53 +70,42 @@ void atomic64_set(atomic64_t *v, long long i) } EXPORT_SYMBOL(atomic64_set); -void atomic64_add(long long a, atomic64_t *v) -{ - unsigned long flags; - raw_spinlock_t *lock = lock_addr(v); - - raw_spin_lock_irqsave(lock, flags); - v->counter += a; - raw_spin_unlock_irqrestore(lock, flags); -} -EXPORT_SYMBOL(atomic64_add); - -long long atomic64_add_return(long long a, atomic64_t *v) -{ - unsigned long flags; - raw_spinlock_t *lock = lock_addr(v); - long long val; - - raw_spin_lock_irqsave(lock, flags); - val = v->counter += a; - raw_spin_unlock_irqrestore(lock, flags); - return val; -} -EXPORT_SYMBOL(atomic64_add_return); - -void atomic64_sub(long long a, atomic64_t *v) -{ - unsigned long flags; - raw_spinlock_t *lock = lock_addr(v); - - raw_spin_lock_irqsave(lock, flags); - v->counter -= a; - raw_spin_unlock_irqrestore(lock, flags); -} -EXPORT_SYMBOL(atomic64_sub); - -long long atomic64_sub_return(long long a, atomic64_t *v) -{ - unsigned long flags; - raw_spinlock_t *lock = lock_addr(v); - long long val; - - raw_spin_lock_irqsave(lock, flags); - val = v->counter -= a; - raw_spin_unlock_irqrestore(lock, flags); - return val; -} -EXPORT_SYMBOL(atomic64_sub_return); +#define ATOMIC64_OP(op, c_op) \ +void atomic64_##op(long long a, atomic64_t *v) \ +{ \ + unsigned long flags; \ + raw_spinlock_t *lock = lock_addr(v); \ + \ + raw_spin_lock_irqsave(lock, flags); \ + v->counter c_op a; \ + raw_spin_unlock_irqrestore(lock, flags); \ +} \ +EXPORT_SYMBOL(atomic64_##op); + +#define ATOMIC64_OP_RETURN(op, c_op) \ +long long atomic64_##op##_return(long long a, atomic64_t *v) \ +{ \ + unsigned long flags; \ + raw_spinlock_t *lock = lock_addr(v); \ + long long val; \ + \ + raw_spin_lock_irqsave(lock, flags); \ + val = (v->counter c_op a); \ + raw_spin_unlock_irqrestore(lock, flags); \ + return val; \ +} \ +EXPORT_SYMBOL(atomic64_##op##_return); + +#define ATOMIC64_OPS(op, c_op) \ + ATOMIC64_OP(op, c_op) \ + ATOMIC64_OP_RETURN(op, c_op) + +ATOMIC64_OPS(add, +=) +ATOMIC64_OPS(sub, -=) + +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP long long atomic64_dec_if_positive(atomic64_t *v) { -- GitLab From ebc3282409ae4d1e90c2f9608665cc4d8fbf7e73 Mon Sep 17 00:00:00 2001 From: Sagar Kamble Date: Wed, 13 Aug 2014 23:07:05 +0530 Subject: [PATCH 0300/5088] drm/i915: Created common handler for platform specific suspend/resume With this change, intel_runtime_suspend and intel_runtime_resume functions become completely platform agnostic. Platform specific suspend/resume changes are moved to intel_suspend_complete and intel_resume_prepare. Cc: Imre Deak Cc: Paulo Zanoni Cc: Daniel Vetter Cc: Jani Nikula Cc: Goel, Akash Signed-off-by: Sagar Kamble Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 76 +++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 01de97776d81..b06e975dba39 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -494,6 +494,10 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) return true; } + +static int intel_suspend_complete(struct drm_i915_private *dev_priv); +static int intel_resume_prepare(struct drm_i915_private *dev_priv); + static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -959,14 +963,14 @@ static int i915_pm_poweroff(struct device *dev) return i915_drm_freeze(drm_dev); } -static int hsw_runtime_suspend(struct drm_i915_private *dev_priv) +static int hsw_suspend_complete(struct drm_i915_private *dev_priv) { hsw_enable_pc8(dev_priv); return 0; } -static int snb_runtime_resume(struct drm_i915_private *dev_priv) +static int snb_resume_prepare(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -975,7 +979,7 @@ static int snb_runtime_resume(struct drm_i915_private *dev_priv) return 0; } -static int hsw_runtime_resume(struct drm_i915_private *dev_priv) +static int hsw_resume_prepare(struct drm_i915_private *dev_priv) { hsw_disable_pc8(dev_priv); @@ -1271,7 +1275,7 @@ static void vlv_check_no_gt_access(struct drm_i915_private *dev_priv) I915_WRITE(VLV_GTLC_PW_STATUS, VLV_GTLC_ALLOWWAKEERR); } -static int vlv_runtime_suspend(struct drm_i915_private *dev_priv) +static int vlv_suspend_complete(struct drm_i915_private *dev_priv) { u32 mask; int err; @@ -1311,7 +1315,7 @@ static int vlv_runtime_suspend(struct drm_i915_private *dev_priv) return err; } -static int vlv_runtime_resume(struct drm_i915_private *dev_priv) +static int vlv_resume_prepare(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; int err; @@ -1389,17 +1393,7 @@ static int intel_runtime_suspend(struct device *device) cancel_work_sync(&dev_priv->rps.work); intel_runtime_pm_disable_interrupts(dev); - if (IS_GEN6(dev)) { - ret = 0; - } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { - ret = hsw_runtime_suspend(dev_priv); - } else if (IS_VALLEYVIEW(dev)) { - ret = vlv_runtime_suspend(dev_priv); - } else { - ret = -ENODEV; - WARN_ON(1); - } - + ret = intel_suspend_complete(dev_priv); if (ret) { DRM_ERROR("Runtime suspend failed, disabling it (%d)\n", ret); intel_runtime_pm_restore_interrupts(dev); @@ -1437,17 +1431,7 @@ static int intel_runtime_resume(struct device *device) intel_opregion_notify_adapter(dev, PCI_D0); dev_priv->pm.suspended = false; - if (IS_GEN6(dev)) { - ret = snb_runtime_resume(dev_priv); - } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { - ret = hsw_runtime_resume(dev_priv); - } else if (IS_VALLEYVIEW(dev)) { - ret = vlv_runtime_resume(dev_priv); - } else { - WARN_ON(1); - ret = -ENODEV; - } - + ret = intel_resume_prepare(dev_priv); /* * No point of rolling back things in case of an error, as the best * we can do is to hope that things will still work (and disable RPM). @@ -1466,6 +1450,44 @@ static int intel_runtime_resume(struct device *device) return ret; } +static int intel_suspend_complete(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + int ret; + + if (IS_GEN6(dev)) { + ret = 0; + } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + ret = hsw_suspend_complete(dev_priv); + } else if (IS_VALLEYVIEW(dev)) { + ret = vlv_suspend_complete(dev_priv); + } else { + ret = -ENODEV; + WARN_ON(1); + } + + return ret; +} + +static int intel_resume_prepare(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + int ret; + + if (IS_GEN6(dev)) { + ret = snb_resume_prepare(dev_priv); + } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + ret = hsw_resume_prepare(dev_priv); + } else if (IS_VALLEYVIEW(dev)) { + ret = vlv_resume_prepare(dev_priv); + } else { + WARN_ON(1); + ret = -ENODEV; + } + + return ret; +} + static const struct dev_pm_ops i915_pm_ops = { .suspend = i915_pm_suspend, .suspend_late = i915_pm_suspend_late, -- GitLab From 016970beb05da6285c2f3ed2bee1c676cb75972e Mon Sep 17 00:00:00 2001 From: Sagar Kamble Date: Wed, 13 Aug 2014 23:07:06 +0530 Subject: [PATCH 0301/5088] drm/i915: Sharing platform specific sequence between runtime and system suspend/ resume paths On VLV, post S0i3 during i915_drm_thaw following issue is observed during ring initialization. [ 335.604039] [drm:stop_ring] ERROR render ring :timed out trying to stop ring [ 336.607340] [drm:stop_ring] ERROR render ring :timed out trying to stop ring [ 336.607345] [drm:init_ring_common] ERROR failed to set render ring head to zero ctl 00000000 head 00000000 tail 00000000 start 00000000 [ 337.610645] [drm:stop_ring] ERROR bsd ring :timed out trying to stop ring [ 338.613952] [drm:stop_ring] ERROR bsd ring :timed out trying to stop ring [ 338.613956] [drm:init_ring_common] ERROR failed to set bsd ring head to zero ctl 00000000 head 00000000 tail 00000000 start 00000000 [ 339.617256] [drm:stop_ring] ERROR render ring :timed out trying to stop ring [ 339.617258] -----------[ cut here ]----------- [ 339.617267] WARNING: CPU: 0 PID: 6 at drivers/gpu/drm/i915/intel_ringbuffer.c:1666 intel_cleanup_ring+0xe6/0xf0() [ 339.617396] --[ end trace 5ef5ed1a3c92e2a6 ]-- [ 339.617428] [drm:__i915_drm_thaw] ERROR failed to re-initialize GPU, declaring wedged! This is happening since wake is not enabled and Gunit registers are not restored. For this system suspend/resume paths need to follow save/restore and additional platform specific setup in suspend_complete and resume_prepare. suspend_complete is shared unconditionaly for VLV, HSW, BDW. resume_prepare for HSW and BDW has pc8 disabling which is needed during thaw_early so sharing uncondtionally. For VLV and SNB runtime resume specific sequence exists. Cc: Imre Deak Cc: Paulo Zanoni Cc: Daniel Vetter Cc: Jani Nikula Cc: Goel, Akash Signed-off-by: Sagar Kamble Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 63 ++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b06e975dba39..2f112853c36f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -496,7 +496,8 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) static int intel_suspend_complete(struct drm_i915_private *dev_priv); -static int intel_resume_prepare(struct drm_i915_private *dev_priv); +static int intel_resume_prepare(struct drm_i915_private *dev_priv, + bool rpm_resume); static int i915_drm_freeze(struct drm_device *dev) { @@ -604,15 +605,17 @@ int i915_suspend(struct drm_device *dev, pm_message_t state) static int i915_drm_thaw_early(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + int ret; - if (IS_HASWELL(dev) || IS_BROADWELL(dev)) - hsw_disable_pc8(dev_priv); + ret = intel_resume_prepare(dev_priv, false); + if (ret) + DRM_ERROR("Resume prepare failed: %d,Continuing resume\n", ret); intel_uncore_early_sanitize(dev, true); intel_uncore_sanitize(dev); intel_power_domains_init_hw(dev_priv); - return 0; + return ret; } static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) @@ -888,6 +891,7 @@ static int i915_pm_suspend_late(struct device *dev) struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); struct drm_i915_private *dev_priv = drm_dev->dev_private; + int ret; /* * We have a suspedn ordering issue with the snd-hda driver also @@ -901,13 +905,16 @@ static int i915_pm_suspend_late(struct device *dev) if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; - if (IS_HASWELL(drm_dev) || IS_BROADWELL(drm_dev)) - hsw_enable_pc8(dev_priv); + ret = intel_suspend_complete(dev_priv); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); + if (ret) + DRM_ERROR("Suspend complete failed: %d\n", ret); + else { + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + } - return 0; + return ret; } static int i915_pm_resume_early(struct device *dev) @@ -970,16 +977,19 @@ static int hsw_suspend_complete(struct drm_i915_private *dev_priv) return 0; } -static int snb_resume_prepare(struct drm_i915_private *dev_priv) +static int snb_resume_prepare(struct drm_i915_private *dev_priv, + bool rpm_resume) { struct drm_device *dev = dev_priv->dev; - intel_init_pch_refclk(dev); + if (rpm_resume) + intel_init_pch_refclk(dev); return 0; } -static int hsw_resume_prepare(struct drm_i915_private *dev_priv) +static int hsw_resume_prepare(struct drm_i915_private *dev_priv, + bool rpm_resume) { hsw_disable_pc8(dev_priv); @@ -1315,7 +1325,8 @@ static int vlv_suspend_complete(struct drm_i915_private *dev_priv) return err; } -static int vlv_resume_prepare(struct drm_i915_private *dev_priv) +static int vlv_resume_prepare(struct drm_i915_private *dev_priv, + bool rpm_resume) { struct drm_device *dev = dev_priv->dev; int err; @@ -1340,8 +1351,10 @@ static int vlv_resume_prepare(struct drm_i915_private *dev_priv) vlv_check_no_gt_access(dev_priv); - intel_init_clock_gating(dev); - i915_gem_restore_fences(dev); + if (rpm_resume) { + intel_init_clock_gating(dev); + i915_gem_restore_fences(dev); + } return ret; } @@ -1431,7 +1444,7 @@ static int intel_runtime_resume(struct device *device) intel_opregion_notify_adapter(dev, PCI_D0); dev_priv->pm.suspended = false; - ret = intel_resume_prepare(dev_priv); + ret = intel_resume_prepare(dev_priv, true); /* * No point of rolling back things in case of an error, as the best * we can do is to hope that things will still work (and disable RPM). @@ -1450,6 +1463,10 @@ static int intel_runtime_resume(struct device *device) return ret; } +/* + * This function implements common functionality of runtime and system + * suspend sequence. + */ static int intel_suspend_complete(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -1469,17 +1486,23 @@ static int intel_suspend_complete(struct drm_i915_private *dev_priv) return ret; } -static int intel_resume_prepare(struct drm_i915_private *dev_priv) +/* + * This function implements common functionality of runtime and system + * resume sequence. Variable rpm_resume used for implementing different + * code paths. + */ +static int intel_resume_prepare(struct drm_i915_private *dev_priv, + bool rpm_resume) { struct drm_device *dev = dev_priv->dev; int ret; if (IS_GEN6(dev)) { - ret = snb_resume_prepare(dev_priv); + ret = snb_resume_prepare(dev_priv, rpm_resume); } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { - ret = hsw_resume_prepare(dev_priv); + ret = hsw_resume_prepare(dev_priv, rpm_resume); } else if (IS_VALLEYVIEW(dev)) { - ret = vlv_resume_prepare(dev_priv); + ret = vlv_resume_prepare(dev_priv, rpm_resume); } else { WARN_ON(1); ret = -ENODEV; -- GitLab From 3a448734902359113b0c7c3454ce4cd56dc1e61f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 12 Aug 2014 20:05:47 +0100 Subject: [PATCH 0302/5088] drm/i915: Print captured bo for all VM in error state The current error state harks back to the era of just a single VM. For full-ppgtt, we capture every bo on every VM. It behoves us to then print every bo for every VM, which we currently fail to do and so miss vital information in the error state. v2: Use the vma address rather than -1! Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_gpu_error.c | 80 +++++++++++++++++++-------- 2 files changed, 58 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 541fb6f295bb..ed52ac744105 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -396,6 +396,7 @@ struct drm_i915_error_state { pid_t pid; char comm[TASK_COMM_LEN]; } ring[I915_NUM_RINGS]; + struct drm_i915_error_buffer { u32 size; u32 name; @@ -414,6 +415,7 @@ struct drm_i915_error_state { } **active_bo, **pinned_bo; u32 *active_bo_count, *pinned_bo_count; + u32 vm_count; }; struct intel_connector; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index fc11ac6b0373..35e70d5d6282 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -192,10 +192,10 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m, struct drm_i915_error_buffer *err, int count) { - err_printf(m, "%s [%d]:\n", name, count); + err_printf(m, " %s [%d]:\n", name, count); while (count--) { - err_printf(m, " %08x %8u %02x %02x %x %x", + err_printf(m, " %08x %8u %02x %02x %x %x", err->gtt_offset, err->size, err->read_domains, @@ -393,15 +393,17 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, i915_ring_error_state(m, dev, &error->ring[i]); } - if (error->active_bo) + for (i = 0; i < error->vm_count; i++) { + err_printf(m, "vm[%d]\n", i); + print_error_buffers(m, "Active", - error->active_bo[0], - error->active_bo_count[0]); + error->active_bo[i], + error->active_bo_count[i]); - if (error->pinned_bo) print_error_buffers(m, "Pinned", - error->pinned_bo[0], - error->pinned_bo_count[0]); + error->pinned_bo[i], + error->pinned_bo_count[i]); + } for (i = 0; i < ARRAY_SIZE(error->ring); i++) { obj = error->ring[i].batchbuffer; @@ -644,13 +646,15 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv, (src)->base.size>>PAGE_SHIFT) static void capture_bo(struct drm_i915_error_buffer *err, - struct drm_i915_gem_object *obj) + struct i915_vma *vma) { + struct drm_i915_gem_object *obj = vma->obj; + err->size = obj->base.size; err->name = obj->base.name; err->rseqno = obj->last_read_seqno; err->wseqno = obj->last_write_seqno; - err->gtt_offset = i915_gem_obj_ggtt_offset(obj); + err->gtt_offset = vma->node.start; err->read_domains = obj->base.read_domains; err->write_domain = obj->base.write_domain; err->fence_reg = obj->fence_reg; @@ -674,7 +678,7 @@ static u32 capture_active_bo(struct drm_i915_error_buffer *err, int i = 0; list_for_each_entry(vma, head, mm_list) { - capture_bo(err++, vma->obj); + capture_bo(err++, vma); if (++i == count) break; } @@ -683,21 +687,27 @@ static u32 capture_active_bo(struct drm_i915_error_buffer *err, } static u32 capture_pinned_bo(struct drm_i915_error_buffer *err, - int count, struct list_head *head) + int count, struct list_head *head, + struct i915_address_space *vm) { struct drm_i915_gem_object *obj; - int i = 0; + struct drm_i915_error_buffer * const first = err; + struct drm_i915_error_buffer * const last = err + count; list_for_each_entry(obj, head, global_list) { - if (!i915_gem_obj_is_pinned(obj)) - continue; + struct i915_vma *vma; - capture_bo(err++, obj); - if (++i == count) + if (err == last) break; + + list_for_each_entry(vma, &obj->vma_list, vma_link) + if (vma->vm == vm && vma->pin_count > 0) { + capture_bo(err++, vma); + break; + } } - return i; + return err - first; } /* Generate a semi-unique error code. The code is not meant to have meaning, The @@ -1053,9 +1063,14 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv, list_for_each_entry(vma, &vm->active_list, mm_list) i++; error->active_bo_count[ndx] = i; - list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) - if (i915_gem_obj_is_pinned(obj)) - i++; + + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { + list_for_each_entry(vma, &obj->vma_list, vma_link) + if (vma->vm == vm && vma->pin_count > 0) { + i++; + break; + } + } error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx]; if (i) { @@ -1074,7 +1089,7 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv, error->pinned_bo_count[ndx] = capture_pinned_bo(pinned_bo, error->pinned_bo_count[ndx], - &dev_priv->mm.bound_list); + &dev_priv->mm.bound_list, vm); error->active_bo[ndx] = active_bo; error->pinned_bo[ndx] = pinned_bo; } @@ -1095,8 +1110,25 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv, error->pinned_bo_count = kcalloc(cnt, sizeof(*error->pinned_bo_count), GFP_ATOMIC); - list_for_each_entry(vm, &dev_priv->vm_list, global_link) - i915_gem_capture_vm(dev_priv, error, vm, i++); + if (error->active_bo == NULL || + error->pinned_bo == NULL || + error->active_bo_count == NULL || + error->pinned_bo_count == NULL) { + kfree(error->active_bo); + kfree(error->active_bo_count); + kfree(error->pinned_bo); + kfree(error->pinned_bo_count); + + error->active_bo = NULL; + error->active_bo_count = NULL; + error->pinned_bo = NULL; + error->pinned_bo_count = NULL; + } else { + list_for_each_entry(vm, &dev_priv->vm_list, global_link) + i915_gem_capture_vm(dev_priv, error, vm, i++); + + error->vm_count = cnt; + } } /* Capture all registers which don't fit into another category. */ -- GitLab From 582d67f0b19afc2299bc8977aba835d8d25bb591 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:16 +0100 Subject: [PATCH 0303/5088] drm/i915: Add temporary ring->ctx backpointer The execlist patches have a bit a convoluted and long history and due to that have the actual submission still misplaced deeply burried in the low-level ringbuffer handling code. This design goes back to the legacy ringbuffer code with its tricky lazy request and simple work submissiion using ring tail writes. For that reason they need a ring->ctx backpointer. The goal is to unburry that code and move it up into a level where the full execlist context is available so that we can ditch this backpointer. Until that's done make it really obvious that there's work still to be done. Cc: Oscar Mateo Cc: Thomas Daniel Acked-by: Thomas Daniel Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 2 ++ drivers/gpu/drm/i915/intel_ringbuffer.h | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 6b5f416b5c0d..c2352d1b23fa 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1086,6 +1086,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, } ringbuf->ring = ring; + ringbuf->FIXME_lrc_ctx = ctx; + ringbuf->size = 32 * PAGE_SIZE; ringbuf->effective_size = ringbuf->size; ringbuf->head = 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 24437da91f77..26785ca72530 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -99,6 +99,13 @@ struct intel_ringbuffer { struct intel_engine_cs *ring; + /* + * FIXME: This backpointer is an artifact of the history of how the + * execlist patches came into being. It will get removed once the basic + * code has landed. + */ + struct intel_context *FIXME_lrc_ctx; + u32 head; u32 tail; int space; -- GitLab From 295ee85316aedfe1878306d71b5e9c7d4498fb1b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 30 Jul 2014 14:23:44 +0200 Subject: [PATCH 0304/5088] drm: Docbook fixes Bunch of small leftovers spotted by looking at the make htmldocs output. I've left out dp mst, there's too much amiss there. v2: Also add the missing parameter docbook in the dp mst code - Dave Airlie correctly pointed out that we don't actually want kerneldoc for the missing structure members in header files. Cc: Dave Airlie Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 5 +++-- drivers/gpu/drm/drm_dp_mst_topology.c | 1 + drivers/gpu/drm/drm_edid.c | 2 +- drivers/gpu/drm/drm_modeset_lock.c | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 285e62a134b2..f09b75212081 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3512,9 +3512,10 @@ EXPORT_SYMBOL(drm_property_create_enum); * @flags: flags specifying the property type * @name: name of the property * @props: enumeration lists with property bitflags - * @num_values: number of pre-defined values + * @num_props: size of the @props array + * @supported_bits: bitmask of all supported enumeration values * - * This creates a new generic drm property which can then be attached to a drm + * This creates a new bitmask drm property which can then be attached to a drm * object with drm_object_attach_property. The returned property object must be * freed with drm_property_destroy. * diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index ac3c2738db94..352f5d6c763c 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2071,6 +2071,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) * drm_dp_mst_hpd_irq() - MST hotplug IRQ notify * @mgr: manager to notify irq for. * @esi: 4 bytes from SINK_COUNT_ESI + * @handled: whether the hpd interrupt was consumed or not * * This should be called from the driver when it detects a short IRQ, * along with the value of the DEVICE_SERVICE_IRQ_VECTOR_ESI0. The diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 1dbf3bc4c6a3..f905c63c0f68 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3433,10 +3433,10 @@ EXPORT_SYMBOL(drm_rgb_quant_range_selectable); /** * drm_assign_hdmi_deep_color_info - detect whether monitor supports * hdmi deep color modes and update drm_display_info if so. - * * @edid: monitor EDID information * @info: Updated with maximum supported deep color bpc and color format * if deep color supported. + * @connector: DRM connector, used only for debug output * * Parse the CEA extension according to CEA-861-B. * Return true if HDMI deep color supported, false if not or unknown. diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 5280b64a0230..8749fc06570e 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -199,7 +199,7 @@ EXPORT_SYMBOL(drm_modeset_lock_crtc); /** * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls - * crtc: drm crtc + * @crtc: drm crtc * * Legacy ioctl operations like cursor updates or page flips only have per-crtc * locking, and store the acquire ctx in the corresponding crtc. All other -- GitLab From c11cda52193dfa459dfea38f00b19bc9325fa922 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 8 Aug 2014 18:50:18 +0100 Subject: [PATCH 0305/5088] drm: Don't return 0 for a value used as a denominator Static analysis will be unhappy if a function can theoretically return 0 and we're trying to divide by that value. Mark that case that cannot occur as a BUG() instead. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_dp_mst_topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 352f5d6c763c..b3adf1445020 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1772,7 +1772,7 @@ static int drm_dp_get_vc_payload_bw(int dp_link_bw, int dp_link_count) case DP_LINK_BW_5_4: return 10 * dp_link_count; } - return 0; + BUG(); } /** -- GitLab From 14f476fa24e81d0beea1aa14d763102958518d60 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 8 Aug 2014 19:15:20 +0100 Subject: [PATCH 0306/5088] drm: Use the type of the array element when reallocating Static analysers find it 'suspicious', that we're trying to allocate memory for elements of size sizeof(struct drm_fb_helper_connector) when the array is defined as struct drm_fb_helper_connector **. Use sizeof(struct drm_fb_helper_connector *) instead. Note that the structure being defined as: struct drm_fb_helper_connector { struct drm_connector *connector; }; This was still doing the right thing, but may not in the future if additional fields are added. Cc: Todd Previte Cc: Dave Airlie Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 7b7b9565188f..6019392b19cc 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -126,7 +126,7 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_ WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { - temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector) * (fb_helper->connector_count + 1), GFP_KERNEL); + temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL); if (!temp) return -ENOMEM; -- GitLab From 48e29f5535b9eb506c44bd8f41bd9348fd219435 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:29 +0100 Subject: [PATCH 0307/5088] drm/i915/bdw: Emission of requests with logical rings On a previous iteration of this patch, I created an Execlists version of __i915_add_request and asbtracted it away as a vfunc. Daniel Vetter wondered then why that was needed: "with the clean split in command submission I expect every function to know wether it'll submit to an lrc (everything in intel_lrc.c) or wether it'll submit to a legacy ring (existing code), so I don't see a need for an add_request vfunc." The honest, hairy truth is that this patch is the glue keeping the whole logical ring puzzle together: - i915_add_request is used by intel_ring_idle, which in turn is used by i915_gpu_idle, which in turn is used in several places inside the eviction and gtt codes. - Also, it is used by i915_gem_check_olr, which is littered all over i915_gem.c - ... If I were to duplicate all the code that directly or indirectly uses __i915_add_request, I'll end up creating a separate driver. To show the differences between the existing legacy version and the new Execlists one, this time I have special-cased __i915_add_request instead of adding an add_request vfunc. I hope this helps to untangle this Gordian knot. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Adjust to ringbuf->FIXME_lrc_ctx per the discussion with Thomas Daniel.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 72 +++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_lrc.c | 30 +++++++++++-- drivers/gpu/drm/i915/intel_lrc.h | 1 + 3 files changed, 80 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6c2f0b886eb0..32fa1e9eb844 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2311,10 +2311,21 @@ int __i915_add_request(struct intel_engine_cs *ring, { struct drm_i915_private *dev_priv = ring->dev->dev_private; struct drm_i915_gem_request *request; + struct intel_ringbuffer *ringbuf; u32 request_ring_position, request_start; int ret; - request_start = intel_ring_get_tail(ring->buffer); + request = ring->preallocated_lazy_request; + if (WARN_ON(request == NULL)) + return -ENOMEM; + + if (i915.enable_execlists) { + struct intel_context *ctx = request->ctx; + ringbuf = ctx->engine[ring->id].ringbuf; + } else + ringbuf = ring->buffer; + + request_start = intel_ring_get_tail(ringbuf); /* * Emit any outstanding flushes - execbuf can fail to emit the flush * after having emitted the batchbuffer command. Hence we need to fix @@ -2322,24 +2333,32 @@ int __i915_add_request(struct intel_engine_cs *ring, * is that the flush _must_ happen before the next request, no matter * what. */ - ret = intel_ring_flush_all_caches(ring); - if (ret) - return ret; - - request = ring->preallocated_lazy_request; - if (WARN_ON(request == NULL)) - return -ENOMEM; + if (i915.enable_execlists) { + ret = logical_ring_flush_all_caches(ringbuf); + if (ret) + return ret; + } else { + ret = intel_ring_flush_all_caches(ring); + if (ret) + return ret; + } /* Record the position of the start of the request so that * should we detect the updated seqno part-way through the * GPU processing the request, we never over-estimate the * position of the head. */ - request_ring_position = intel_ring_get_tail(ring->buffer); + request_ring_position = intel_ring_get_tail(ringbuf); - ret = ring->add_request(ring); - if (ret) - return ret; + if (i915.enable_execlists) { + ret = ring->emit_request(ringbuf); + if (ret) + return ret; + } else { + ret = ring->add_request(ring); + if (ret) + return ret; + } request->seqno = intel_ring_get_seqno(ring); request->ring = ring; @@ -2354,12 +2373,14 @@ int __i915_add_request(struct intel_engine_cs *ring, */ request->batch_obj = obj; - /* 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); + 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); + } request->emitted_jiffies = jiffies; list_add_tail(&request->list, &ring->request_list); @@ -2614,6 +2635,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; + struct intel_ringbuffer *ringbuf; request = list_first_entry(&ring->request_list, struct drm_i915_gem_request, @@ -2623,12 +2645,24 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) break; trace_i915_gem_request_retire(ring, request->seqno); + + /* This is one of the few common intersection points + * between legacy ringbuffer submission and execlists: + * we need to tell them apart in order to find the correct + * ringbuffer to which the request belongs to. + */ + if (i915.enable_execlists) { + struct intel_context *ctx = request->ctx; + ringbuf = ctx->engine[ring->id].ringbuf; + } else + ringbuf = ring->buffer; + /* We know the GPU must have read the request to have * sent us the seqno + interrupt, so use the position * of tail of the request to update the last known position * of the GPU head. */ - ring->buffer->last_retired_head = request->tail; + ringbuf->last_retired_head = request->tail; i915_gem_free_request(request); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index c2352d1b23fa..cd6ddd80e54c 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -252,6 +252,22 @@ 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_engine_cs *ring = ringbuf->ring; + int ret; + + if (!ring->gpu_caches_dirty) + return 0; + + ret = ring->emit_flush(ringbuf, 0, I915_GEM_GPU_DOMAINS); + if (ret) + return ret; + + ring->gpu_caches_dirty = false; + return 0; +} + void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf) { intel_logical_ring_advance(ringbuf); @@ -262,7 +278,8 @@ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf) /* TODO: how to submit a context to the ELSP is not here yet */ } -static int logical_ring_alloc_seqno(struct intel_engine_cs *ring) +static int logical_ring_alloc_seqno(struct intel_engine_cs *ring, + struct intel_context *ctx) { if (ring->outstanding_lazy_seqno) return 0; @@ -274,6 +291,13 @@ static int logical_ring_alloc_seqno(struct intel_engine_cs *ring) if (request == NULL) return -ENOMEM; + /* Hold a reference to the context this request belongs to + * (we will need it when the time comes to emit/retire the + * request). + */ + request->ctx = ctx; + i915_gem_context_reference(request->ctx); + ring->preallocated_lazy_request = request; } @@ -312,8 +336,6 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, if (ret) return ret; - /* TODO: make sure we update the right ringbuffer's last_retired_head - * when retiring requests */ i915_gem_retire_requests_ring(ring); ringbuf->head = ringbuf->last_retired_head; ringbuf->last_retired_head = -1; @@ -433,7 +455,7 @@ int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords) return ret; /* Preallocate the olr before touching the ring */ - ret = logical_ring_alloc_seqno(ring); + ret = logical_ring_alloc_seqno(ring, ringbuf->FIXME_lrc_ctx); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 4e032875c1fd..460e1af15600 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -29,6 +29,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); void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf); static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf) { -- GitLab From 84b790f80e5153d8d54074aa4eae49ff3070f2f1 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 24 Jul 2014 17:04:36 +0100 Subject: [PATCH 0308/5088] drm/i915/bdw: Implement context switching (somewhat) A context switch occurs by submitting a context descriptor to the ExecList Submission Port. Given that we can now initialize a context, it's possible to begin implementing the context switch by creating the descriptor and submitting it to ELSP (actually two, since the ELSP has two ports). The context object must be mapped in the GGTT, which means it must exist in the 0-4GB graphics VA range. Signed-off-by: Ben Widawsky v2: This code has changed quite a lot in various rebases. Of particular importance is that now we use the globally unique Submission ID to send to the hardware. Also, context pages are now pinned unconditionally to GGTT, so there is no need to bind them. v3: Use LRCA[31:12] as hwCtxId[19:0]. This guarantees that the HW context ID we submit to the ELSP is globally unique and != 0 (Bspec requirements of the software use-only bits of the Context ID in the Context Descriptor Format) without the hassle of the previous submission Id construction. Also, re-add the ELSP porting read (it was dropped somewhere during the rebases). v4: - Squash with "drm/i915/bdw: Add forcewake lock around ELSP writes" (BSPEC says: "SW must set Force Wakeup bit to prevent GT from entering C6 while ELSP writes are in progress") as noted by Thomas Daniel (thomas.daniel@intel.com). - Rename functions and use an execlists/intel_execlists_ namespace. - The BUG_ON only checked that the LRCA was <32 bits, but it didn't make sure that it was properly aligned. Spotted by Alistair Mcaulay . v5: - Improved source code comments as suggested by Chris Wilson. - No need to abstract submit_ctx away, as pointed by Brad Volkin. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Checkpatch. Sigh.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 116 ++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_lrc.h | 1 + 2 files changed, 115 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index cd6ddd80e54c..aa81fd41b9c1 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -47,6 +47,7 @@ #define GEN8_LR_CONTEXT_ALIGN 4096 #define RING_ELSP(ring) ((ring)->mmio_base+0x230) +#define RING_EXECLIST_STATUS(ring) ((ring)->mmio_base+0x234) #define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244) #define CTX_LRI_HEADER_0 0x01 @@ -78,6 +79,26 @@ #define CTX_R_PWR_CLK_STATE 0x42 #define CTX_GPGPU_CSR_BASE_ADDRESS 0x44 +#define GEN8_CTX_VALID (1<<0) +#define GEN8_CTX_FORCE_PD_RESTORE (1<<1) +#define GEN8_CTX_FORCE_RESTORE (1<<2) +#define GEN8_CTX_L3LLC_COHERENT (1<<5) +#define GEN8_CTX_PRIVILEGE (1<<8) +enum { + ADVANCED_CONTEXT = 0, + LEGACY_CONTEXT, + ADVANCED_AD_CONTEXT, + LEGACY_64B_CONTEXT +}; +#define GEN8_CTX_MODE_SHIFT 3 +enum { + FAULT_AND_HANG = 0, + FAULT_AND_HALT, /* Debug only */ + FAULT_AND_STREAM, + FAULT_AND_CONTINUE /* Unsupported */ +}; +#define GEN8_CTX_ID_SHIFT 32 + int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists) { WARN_ON(i915.enable_ppgtt == -1); @@ -92,6 +113,93 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists return 0; } +u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj) +{ + u32 lrca = i915_gem_obj_ggtt_offset(ctx_obj); + + /* LRCA is required to be 4K aligned so the more significant 20 bits + * are globally unique */ + return lrca >> 12; +} + +static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_object *ctx_obj) +{ + uint64_t desc; + uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj); + BUG_ON(lrca & 0xFFFFFFFF00000FFFULL); + + desc = GEN8_CTX_VALID; + desc |= LEGACY_CONTEXT << GEN8_CTX_MODE_SHIFT; + desc |= GEN8_CTX_L3LLC_COHERENT; + desc |= GEN8_CTX_PRIVILEGE; + desc |= lrca; + desc |= (u64)intel_execlists_ctx_id(ctx_obj) << GEN8_CTX_ID_SHIFT; + + /* TODO: WaDisableLiteRestore when we start using semaphore + * signalling between Command Streamers */ + /* desc |= GEN8_CTX_FORCE_RESTORE; */ + + 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) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + 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(ctx_obj1); + else + temp = 0; + desc[1] = (u32)(temp >> 32); + desc[0] = (u32)temp; + + temp = execlists_ctx_descriptor(ctx_obj0); + desc[3] = (u32)(temp >> 32); + desc[2] = (u32)temp; + + /* Set Force Wakeup bit to prevent GT from entering C6 while + * ELSP writes are in progress */ + gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); + + I915_WRITE(RING_ELSP(ring), desc[1]); + I915_WRITE(RING_ELSP(ring), desc[0]); + I915_WRITE(RING_ELSP(ring), desc[3]); + /* The context is automatically loaded after the following */ + I915_WRITE(RING_ELSP(ring), desc[2]); + + /* ELSP is a wo register, so use another nearby reg for posting instead */ + POSTING_READ(RING_EXECLIST_STATUS(ring)); + + gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); +} + +static int execlists_submit_context(struct intel_engine_cs *ring, + struct intel_context *to0, u32 tail0, + struct intel_context *to1, u32 tail1) +{ + struct drm_i915_gem_object *ctx_obj0; + struct drm_i915_gem_object *ctx_obj1 = NULL; + + ctx_obj0 = to0->engine[ring->id].state; + BUG_ON(!ctx_obj0); + BUG_ON(!i915_gem_obj_is_pinned(ctx_obj0)); + + if (to1) { + ctx_obj1 = to1->engine[ring->id].state; + BUG_ON(!ctx_obj1); + BUG_ON(!i915_gem_obj_is_pinned(ctx_obj1)); + } + + execlists_elsp_write(ring, ctx_obj0, ctx_obj1); + + return 0; +} + static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf) { struct intel_engine_cs *ring = ringbuf->ring; @@ -270,12 +378,16 @@ int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf) void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf) { + struct intel_engine_cs *ring = ringbuf->ring; + struct intel_context *ctx = ringbuf->FIXME_lrc_ctx; + intel_logical_ring_advance(ringbuf); - if (intel_ring_stopped(ringbuf->ring)) + if (intel_ring_stopped(ring)) return; - /* TODO: how to submit a context to the ELSP is not here yet */ + /* FIXME: too cheeky, we don't even check if the ELSP is ready */ + execlists_submit_context(ring, ctx, ringbuf->tail, NULL, 0); } static int logical_ring_alloc_seqno(struct intel_engine_cs *ring, diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 460e1af15600..69605b158235 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -57,5 +57,6 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, struct list_head *vmas, struct drm_i915_gem_object *batch_obj, u64 exec_start, u32 flags); +u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj); #endif /* _INTEL_LRC_H_ */ -- GitLab From ae1250b9da308acd16554365d125b4afb795b825 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:37 +0100 Subject: [PATCH 0309/5088] drm/i915/bdw: Write the tail pointer, LRC style Each logical ring context has the tail pointer in the context object, so update it before submission. v2: New namespace. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index aa81fd41b9c1..26bc063f137b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -178,6 +178,21 @@ static void execlists_elsp_write(struct intel_engine_cs *ring, gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); } +static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tail) +{ + struct page *page; + uint32_t *reg_state; + + page = i915_gem_object_get_page(ctx_obj, 1); + reg_state = kmap_atomic(page); + + reg_state[CTX_RING_TAIL+1] = tail; + + kunmap_atomic(reg_state); + + return 0; +} + static int execlists_submit_context(struct intel_engine_cs *ring, struct intel_context *to0, u32 tail0, struct intel_context *to1, u32 tail1) @@ -189,10 +204,14 @@ static int execlists_submit_context(struct intel_engine_cs *ring, BUG_ON(!ctx_obj0); BUG_ON(!i915_gem_obj_is_pinned(ctx_obj0)); + execlists_ctx_write_tail(ctx_obj0, tail0); + if (to1) { ctx_obj1 = to1->engine[ring->id].state; BUG_ON(!ctx_obj1); BUG_ON(!i915_gem_obj_is_pinned(ctx_obj1)); + + execlists_ctx_write_tail(ctx_obj1, tail1); } execlists_elsp_write(ring, ctx_obj0, ctx_obj1); -- GitLab From acdd884a2e1b873995c120d5eabd8cab77f48f20 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Thu, 24 Jul 2014 17:04:38 +0100 Subject: [PATCH 0310/5088] drm/i915/bdw: Two-stage execlist submit process Context switch (and execlist submission) should happen only when other contexts are not active, otherwise pre-emption occurs. To assure this, we place context switch requests in a queue and those request are later consumed when the right context switch interrupt is received (still TODO). v2: Use a spinlock, do not remove the requests on unqueue (wait for context switch completion). Signed-off-by: Thomas Daniel v3: Several rebases and code changes. Use unique ID. v4: - Move the queue/lock init to the late ring initialization. - Damien's kmalloc review comments: check return, use sizeof(*req), do not cast. v5: - Do not reuse drm_i915_gem_request. Instead, create our own. - New namespace. Signed-off-by: Michel Thierry (v1) Signed-off-by: Oscar Mateo (v2-v5) Reviewed-by: Damien Lespiau [davnet: Checkpatch + wash-up s/BUG_ON/WARN_ON/.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 72 +++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_lrc.h | 8 +++ drivers/gpu/drm/i915/intel_ringbuffer.h | 2 + 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 26bc063f137b..e81f5f6c49b9 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -126,7 +126,8 @@ static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_object *ctx_obj) { uint64_t desc; uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj); - BUG_ON(lrca & 0xFFFFFFFF00000FFFULL); + + WARN_ON(lrca & 0xFFFFFFFF00000FFFULL); desc = GEN8_CTX_VALID; desc |= LEGACY_CONTEXT << GEN8_CTX_MODE_SHIFT; @@ -202,14 +203,14 @@ static int execlists_submit_context(struct intel_engine_cs *ring, ctx_obj0 = to0->engine[ring->id].state; BUG_ON(!ctx_obj0); - BUG_ON(!i915_gem_obj_is_pinned(ctx_obj0)); + WARN_ON(!i915_gem_obj_is_pinned(ctx_obj0)); execlists_ctx_write_tail(ctx_obj0, tail0); if (to1) { ctx_obj1 = to1->engine[ring->id].state; BUG_ON(!ctx_obj1); - BUG_ON(!i915_gem_obj_is_pinned(ctx_obj1)); + WARN_ON(!i915_gem_obj_is_pinned(ctx_obj1)); execlists_ctx_write_tail(ctx_obj1, tail1); } @@ -219,6 +220,65 @@ static int execlists_submit_context(struct intel_engine_cs *ring, return 0; } +static void execlists_context_unqueue(struct intel_engine_cs *ring) +{ + struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL; + struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL; + + if (list_empty(&ring->execlist_queue)) + return; + + /* Try to read in pairs */ + list_for_each_entry_safe(cursor, tmp, &ring->execlist_queue, + execlist_link) { + if (!req0) { + req0 = cursor; + } else if (req0->ctx == cursor->ctx) { + /* Same ctx: ignore first request, as second request + * will update tail past first request's workload */ + list_del(&req0->execlist_link); + i915_gem_context_unreference(req0->ctx); + kfree(req0); + req0 = cursor; + } else { + req1 = cursor; + break; + } + } + + WARN_ON(execlists_submit_context(ring, req0->ctx, req0->tail, + req1 ? req1->ctx : NULL, + req1 ? req1->tail : 0)); +} + +static int execlists_context_queue(struct intel_engine_cs *ring, + struct intel_context *to, + u32 tail) +{ + struct intel_ctx_submit_request *req = NULL; + unsigned long flags; + bool was_empty; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (req == NULL) + return -ENOMEM; + req->ctx = to; + i915_gem_context_reference(req->ctx); + req->ring = ring; + req->tail = tail; + + spin_lock_irqsave(&ring->execlist_lock, flags); + + was_empty = list_empty(&ring->execlist_queue); + list_add_tail(&req->execlist_link, &ring->execlist_queue); + if (was_empty) + execlists_context_unqueue(ring); + + spin_unlock_irqrestore(&ring->execlist_lock, flags); + + return 0; +} + static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf) { struct intel_engine_cs *ring = ringbuf->ring; @@ -405,8 +465,7 @@ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf) if (intel_ring_stopped(ring)) return; - /* FIXME: too cheeky, we don't even check if the ELSP is ready */ - execlists_submit_context(ring, ctx, ringbuf->tail, NULL, 0); + execlists_context_queue(ring, ctx, ringbuf->tail); } static int logical_ring_alloc_seqno(struct intel_engine_cs *ring, @@ -846,6 +905,9 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin INIT_LIST_HEAD(&ring->request_list); init_waitqueue_head(&ring->irq_queue); + INIT_LIST_HEAD(&ring->execlist_queue); + spin_lock_init(&ring->execlist_lock); + ret = intel_lr_context_deferred_create(dctx, ring); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 69605b158235..3c389b3a2b75 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -59,4 +59,12 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, u64 exec_start, u32 flags); u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj); +struct intel_ctx_submit_request { + struct intel_context *ctx; + struct intel_engine_cs *ring; + u32 tail; + + struct list_head execlist_link; +}; + #endif /* _INTEL_LRC_H_ */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 26785ca72530..670262dabb6c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -231,6 +231,8 @@ struct intel_engine_cs { } semaphore; /* Execlists */ + spinlock_t execlist_lock; + struct list_head execlist_queue; u32 irq_keep_mask; /* bitmask for interrupts that should not be masked */ int (*emit_request)(struct intel_ringbuffer *ringbuf); int (*emit_flush)(struct intel_ringbuffer *ringbuf, -- GitLab From e981e7b17f2b41970e7e2367d4225e0bb3310667 Mon Sep 17 00:00:00 2001 From: Thomas Daniel Date: Thu, 24 Jul 2014 17:04:39 +0100 Subject: [PATCH 0311/5088] drm/i915/bdw: Handle context switch events Handle all context status events in the context status buffer on every context switch interrupt. We only remove work from the execlist queue after a context status buffer reports that it has completed and we only attempt to schedule new contexts on interrupt when a previously submitted context completes (unless no contexts are queued, which means the GPU is free). We canot call intel_runtime_pm_get() in an interrupt (or with a spinlock grabbed, FWIW), because it might sleep, which is not a nice thing to do. Instead, do the runtime_pm get/put together with the create/destroy request, and handle the forcewake get/put directly. Signed-off-by: Thomas Daniel v2: Unreferencing the context when we are freeing the request might free the backing bo, which requires the struct_mutex to be grabbed, so defer unreferencing and freeing to a bottom half. v3: - Ack the interrupt inmediately, before trying to handle it (fix for missing interrupts by Bob Beckett ). - Update the Context Status Buffer Read Pointer, just in case (spotted by Damien Lespiau). v4: New namespace and multiple rebase changes. v5: Squash with "drm/i915/bdw: Do not call intel_runtime_pm_get() in an interrupt", as suggested by Daniel. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Checkpatch ...] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 35 +++++-- drivers/gpu/drm/i915/intel_lrc.c | 133 ++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_lrc.h | 3 + drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 4 files changed, 155 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 00957fa0b877..f5d6795887d2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1632,6 +1632,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, struct drm_i915_private *dev_priv, u32 master_ctl) { + struct intel_engine_cs *ring; u32 rcs, bcs, vcs; uint32_t tmp = 0; irqreturn_t ret = IRQ_NONE; @@ -1641,14 +1642,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, if (tmp) { I915_WRITE(GEN8_GT_IIR(0), tmp); ret = IRQ_HANDLED; + rcs = tmp >> GEN8_RCS_IRQ_SHIFT; - bcs = tmp >> GEN8_BCS_IRQ_SHIFT; + ring = &dev_priv->ring[RCS]; if (rcs & GT_RENDER_USER_INTERRUPT) - notify_ring(dev, &dev_priv->ring[RCS]); + notify_ring(dev, ring); + if (rcs & GT_CONTEXT_SWITCH_INTERRUPT) + intel_execlists_handle_ctx_events(ring); + + bcs = tmp >> GEN8_BCS_IRQ_SHIFT; + ring = &dev_priv->ring[BCS]; if (bcs & GT_RENDER_USER_INTERRUPT) - notify_ring(dev, &dev_priv->ring[BCS]); - if ((rcs | bcs) & GT_CONTEXT_SWITCH_INTERRUPT) - DRM_DEBUG_DRIVER("TODO: Context switch\n"); + notify_ring(dev, ring); + if (bcs & GT_CONTEXT_SWITCH_INTERRUPT) + intel_execlists_handle_ctx_events(ring); } else DRM_ERROR("The master control interrupt lied (GT0)!\n"); } @@ -1658,16 +1665,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, if (tmp) { I915_WRITE(GEN8_GT_IIR(1), tmp); ret = IRQ_HANDLED; + vcs = tmp >> GEN8_VCS1_IRQ_SHIFT; + ring = &dev_priv->ring[VCS]; if (vcs & GT_RENDER_USER_INTERRUPT) - notify_ring(dev, &dev_priv->ring[VCS]); + notify_ring(dev, ring); if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) - DRM_DEBUG_DRIVER("TODO: Context switch\n"); + intel_execlists_handle_ctx_events(ring); + vcs = tmp >> GEN8_VCS2_IRQ_SHIFT; + ring = &dev_priv->ring[VCS2]; if (vcs & GT_RENDER_USER_INTERRUPT) - notify_ring(dev, &dev_priv->ring[VCS2]); + notify_ring(dev, ring); if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) - DRM_DEBUG_DRIVER("TODO: Context switch\n"); + intel_execlists_handle_ctx_events(ring); } else DRM_ERROR("The master control interrupt lied (GT1)!\n"); } @@ -1688,11 +1699,13 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, if (tmp) { I915_WRITE(GEN8_GT_IIR(3), tmp); ret = IRQ_HANDLED; + vcs = tmp >> GEN8_VECS_IRQ_SHIFT; + ring = &dev_priv->ring[VECS]; if (vcs & GT_RENDER_USER_INTERRUPT) - notify_ring(dev, &dev_priv->ring[VECS]); + notify_ring(dev, ring); if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) - DRM_DEBUG_DRIVER("TODO: Context switch\n"); + intel_execlists_handle_ctx_events(ring); } else DRM_ERROR("The master control interrupt lied (GT3)!\n"); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index e81f5f6c49b9..22f6a7c0cb18 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -49,6 +49,22 @@ #define RING_ELSP(ring) ((ring)->mmio_base+0x230) #define RING_EXECLIST_STATUS(ring) ((ring)->mmio_base+0x234) #define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244) +#define RING_CONTEXT_STATUS_BUF(ring) ((ring)->mmio_base+0x370) +#define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0) + +#define RING_EXECLIST_QFULL (1 << 0x2) +#define RING_EXECLIST1_VALID (1 << 0x3) +#define RING_EXECLIST0_VALID (1 << 0x4) +#define RING_EXECLIST_ACTIVE_STATUS (3 << 0xE) +#define RING_EXECLIST1_ACTIVE (1 << 0x11) +#define RING_EXECLIST0_ACTIVE (1 << 0x12) + +#define GEN8_CTX_STATUS_IDLE_ACTIVE (1 << 0) +#define GEN8_CTX_STATUS_PREEMPTED (1 << 1) +#define GEN8_CTX_STATUS_ELEMENT_SWITCH (1 << 2) +#define GEN8_CTX_STATUS_ACTIVE_IDLE (1 << 3) +#define GEN8_CTX_STATUS_COMPLETE (1 << 4) +#define GEN8_CTX_STATUS_LITE_RESTORE (1 << 15) #define CTX_LRI_HEADER_0 0x01 #define CTX_CONTEXT_CONTROL 0x02 @@ -150,6 +166,7 @@ static void execlists_elsp_write(struct intel_engine_cs *ring, struct drm_i915_private *dev_priv = ring->dev->dev_private; uint64_t temp = 0; uint32_t desc[4]; + unsigned long flags; /* XXX: You must always write both descriptors in the order below. */ if (ctx_obj1) @@ -163,9 +180,17 @@ static void execlists_elsp_write(struct intel_engine_cs *ring, desc[3] = (u32)(temp >> 32); desc[2] = (u32)temp; - /* Set Force Wakeup bit to prevent GT from entering C6 while - * ELSP writes are in progress */ - gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); + /* Set Force Wakeup bit to prevent GT from entering C6 while ELSP writes + * are in progress. + * + * The other problem is that we can't just call gen6_gt_force_wake_get() + * because that function calls intel_runtime_pm_get(), which might sleep. + * Instead, we do the runtime_pm_get/put when creating/destroying requests. + */ + spin_lock_irqsave(&dev_priv->uncore.lock, flags); + if (dev_priv->uncore.forcewake_count++ == 0) + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL); + spin_unlock_irqrestore(&dev_priv->uncore.lock, flags); I915_WRITE(RING_ELSP(ring), desc[1]); I915_WRITE(RING_ELSP(ring), desc[0]); @@ -176,7 +201,11 @@ static void execlists_elsp_write(struct intel_engine_cs *ring, /* ELSP is a wo register, so use another nearby reg for posting instead */ POSTING_READ(RING_EXECLIST_STATUS(ring)); - gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); + /* Release Force Wakeup (see the big comment above). */ + spin_lock_irqsave(&dev_priv->uncore.lock, flags); + if (--dev_priv->uncore.forcewake_count == 0) + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL); + spin_unlock_irqrestore(&dev_priv->uncore.lock, flags); } static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tail) @@ -224,6 +253,9 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring) { struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL; struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL; + struct drm_i915_private *dev_priv = ring->dev->dev_private; + + assert_spin_locked(&ring->execlist_lock); if (list_empty(&ring->execlist_queue)) return; @@ -237,8 +269,7 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring) /* Same ctx: ignore first request, as second request * will update tail past first request's workload */ list_del(&req0->execlist_link); - i915_gem_context_unreference(req0->ctx); - kfree(req0); + queue_work(dev_priv->wq, &req0->work); req0 = cursor; } else { req1 = cursor; @@ -251,11 +282,97 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring) req1 ? req1->tail : 0)); } +static bool execlists_check_remove_request(struct intel_engine_cs *ring, + u32 request_id) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct intel_ctx_submit_request *head_req; + + assert_spin_locked(&ring->execlist_lock); + + head_req = list_first_entry_or_null(&ring->execlist_queue, + struct intel_ctx_submit_request, + execlist_link); + + if (head_req != NULL) { + struct drm_i915_gem_object *ctx_obj = + head_req->ctx->engine[ring->id].state; + if (intel_execlists_ctx_id(ctx_obj) == request_id) { + list_del(&head_req->execlist_link); + queue_work(dev_priv->wq, &head_req->work); + return true; + } + } + + return false; +} + +void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + u32 status_pointer; + u8 read_pointer; + u8 write_pointer; + u32 status; + u32 status_id; + u32 submit_contexts = 0; + + status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring)); + + read_pointer = ring->next_context_status_buffer; + write_pointer = status_pointer & 0x07; + if (read_pointer > write_pointer) + write_pointer += 6; + + spin_lock(&ring->execlist_lock); + + while (read_pointer < write_pointer) { + read_pointer++; + status = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + + (read_pointer % 6) * 8); + status_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + + (read_pointer % 6) * 8 + 4); + + if (status & GEN8_CTX_STATUS_COMPLETE) { + if (execlists_check_remove_request(ring, status_id)) + submit_contexts++; + } + } + + if (submit_contexts != 0) + execlists_context_unqueue(ring); + + spin_unlock(&ring->execlist_lock); + + WARN(submit_contexts > 2, "More than two context complete events?\n"); + ring->next_context_status_buffer = write_pointer % 6; + + I915_WRITE(RING_CONTEXT_STATUS_PTR(ring), + ((u32)ring->next_context_status_buffer & 0x07) << 8); +} + +static void execlists_free_request_task(struct work_struct *work) +{ + struct intel_ctx_submit_request *req = + container_of(work, struct intel_ctx_submit_request, work); + struct drm_device *dev = req->ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + intel_runtime_pm_put(dev_priv); + + mutex_lock(&dev->struct_mutex); + i915_gem_context_unreference(req->ctx); + mutex_unlock(&dev->struct_mutex); + + kfree(req); +} + static int execlists_context_queue(struct intel_engine_cs *ring, struct intel_context *to, u32 tail) { struct intel_ctx_submit_request *req = NULL; + struct drm_i915_private *dev_priv = ring->dev->dev_private; unsigned long flags; bool was_empty; @@ -266,6 +383,9 @@ static int execlists_context_queue(struct intel_engine_cs *ring, i915_gem_context_reference(req->ctx); req->ring = ring; req->tail = tail; + INIT_WORK(&req->work, execlists_free_request_task); + + intel_runtime_pm_get(dev_priv); spin_lock_irqsave(&ring->execlist_lock, flags); @@ -907,6 +1027,7 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin INIT_LIST_HEAD(&ring->execlist_queue); spin_lock_init(&ring->execlist_lock); + ring->next_context_status_buffer = 0; ret = intel_lr_context_deferred_create(dctx, ring); if (ret) diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 3c389b3a2b75..a3f135cf439e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -65,6 +65,9 @@ struct intel_ctx_submit_request { u32 tail; struct list_head execlist_link; + struct work_struct work; }; +void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring); + #endif /* _INTEL_LRC_H_ */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 670262dabb6c..9cbf7b0ebc99 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -233,6 +233,7 @@ struct intel_engine_cs { /* Execlists */ spinlock_t execlist_lock; struct list_head execlist_queue; + u8 next_context_status_buffer; u32 irq_keep_mask; /* bitmask for interrupts that should not be masked */ int (*emit_request)(struct intel_ringbuffer *ringbuf); int (*emit_flush)(struct intel_ringbuffer *ringbuf, -- GitLab From e1fee72c2ea2e9c0c6e6743d32a6832f21337d6c Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:40 +0100 Subject: [PATCH 0312/5088] drm/i915/bdw: Avoid non-lite-restore preemptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the current Execlists feeding mechanism, full preemption is not supported yet: only lite-restores are allowed (this is: the GPU simply samples a new tail pointer for the context currently in execution). But we have identified an scenario in which a full preemption occurs: 1) We submit two contexts for execution (A & B). 2) The GPU finishes with the first one (A), switches to the second one (B) and informs us. 3) We submit B again (hoping to cause a lite restore) together with C, but in the time we spend writing to the ELSP, the GPU finishes B. 4) The GPU start executing B again (since we told it so). 5) We receive a B finished interrupt and, mistakenly, we submit C (again) and D, causing a full preemption of B. The race is avoided by keeping track of how many times a context has been submitted to the hardware and by better discriminating the received context switch interrupts: in the example, when we have submitted B twice, we won´t submit C and D as soon as we receive the notification that B is completed because we were expecting to get a LITE_RESTORE and we didn´t, so we know a second completion will be received shortly. Without this explicit checking, somehow, the batch buffer execution order gets messed with. This can be verified with the IGT test I sent together with the series. I don´t know the exact mechanism by which the pre-emption messes with the execution order but, since other people is working on the Scheduler + Preemption on Execlists, I didn´t try to fix it. In these series, only Lite Restores are supported (other kind of preemptions WARN). v2: elsp_submitted belongs in the new intel_ctx_submit_request. Several rebase changes. v3: Clarify how the race is avoided, as requested by Daniel. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Align function parameters ...] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 29 +++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_lrc.h | 2 ++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 22f6a7c0cb18..0f1b6b2b0f0e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -268,6 +268,7 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring) } else if (req0->ctx == cursor->ctx) { /* Same ctx: ignore first request, as second request * will update tail past first request's workload */ + cursor->elsp_submitted = req0->elsp_submitted; list_del(&req0->execlist_link); queue_work(dev_priv->wq, &req0->work); req0 = cursor; @@ -277,9 +278,15 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring) } } + WARN_ON(req1 && req1->elsp_submitted); + WARN_ON(execlists_submit_context(ring, req0->ctx, req0->tail, req1 ? req1->ctx : NULL, req1 ? req1->tail : 0)); + + req0->elsp_submitted++; + if (req1) + req1->elsp_submitted++; } static bool execlists_check_remove_request(struct intel_engine_cs *ring, @@ -298,9 +305,14 @@ static bool execlists_check_remove_request(struct intel_engine_cs *ring, struct drm_i915_gem_object *ctx_obj = head_req->ctx->engine[ring->id].state; if (intel_execlists_ctx_id(ctx_obj) == request_id) { - list_del(&head_req->execlist_link); - queue_work(dev_priv->wq, &head_req->work); - return true; + WARN(head_req->elsp_submitted == 0, + "Never submitted head request\n"); + + if (--head_req->elsp_submitted <= 0) { + list_del(&head_req->execlist_link); + queue_work(dev_priv->wq, &head_req->work); + return true; + } } } @@ -333,7 +345,16 @@ void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring) status_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + (read_pointer % 6) * 8 + 4); - if (status & GEN8_CTX_STATUS_COMPLETE) { + if (status & GEN8_CTX_STATUS_PREEMPTED) { + if (status & GEN8_CTX_STATUS_LITE_RESTORE) { + if (execlists_check_remove_request(ring, status_id)) + WARN(1, "Lite Restored request removed from queue\n"); + } else + WARN(1, "Preemption without Lite Restore\n"); + } + + if ((status & GEN8_CTX_STATUS_ACTIVE_IDLE) || + (status & GEN8_CTX_STATUS_ELEMENT_SWITCH)) { if (execlists_check_remove_request(ring, status_id)) submit_contexts++; } diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index a3f135cf439e..331c6c2ba376 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -66,6 +66,8 @@ struct intel_ctx_submit_request { struct list_head execlist_link; struct work_struct work; + + int elsp_submitted; }; void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring); -- GitLab From f1ad5a1fd4127b3a5e21b8f5ef7f1921a5d3063e Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:41 +0100 Subject: [PATCH 0313/5088] drm/i915/bdw: Help out the ctx switch interrupt handler If we receive a storm of requests for the same context (see gem_storedw_loop_*) we might end up iterating over too many elements in interrupt time, looking for contexts to squash together. Instead, share the burden by giving more intelligence to the queue function. At most, the interrupt will iterate over three elements. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Checkpatch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 0f1b6b2b0f0e..6f6c5a931faf 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -392,10 +392,10 @@ static int execlists_context_queue(struct intel_engine_cs *ring, struct intel_context *to, u32 tail) { - struct intel_ctx_submit_request *req = NULL; + struct intel_ctx_submit_request *req = NULL, *cursor; struct drm_i915_private *dev_priv = ring->dev->dev_private; unsigned long flags; - bool was_empty; + int num_elements = 0; req = kzalloc(sizeof(*req), GFP_KERNEL); if (req == NULL) @@ -410,9 +410,27 @@ static int execlists_context_queue(struct intel_engine_cs *ring, spin_lock_irqsave(&ring->execlist_lock, flags); - was_empty = list_empty(&ring->execlist_queue); + list_for_each_entry(cursor, &ring->execlist_queue, execlist_link) + if (++num_elements > 2) + break; + + if (num_elements > 2) { + struct intel_ctx_submit_request *tail_req; + + tail_req = list_last_entry(&ring->execlist_queue, + struct intel_ctx_submit_request, + execlist_link); + + if (to == tail_req->ctx) { + WARN(tail_req->elsp_submitted != 0, + "More than 2 already-submitted reqs queued\n"); + list_del(&tail_req->execlist_link); + queue_work(dev_priv->wq, &tail_req->work); + } + } + list_add_tail(&req->execlist_link, &ring->execlist_queue); - if (was_empty) + if (num_elements == 0) execlists_context_unqueue(ring); spin_unlock_irqrestore(&ring->execlist_lock, flags); -- GitLab From 4ed91096881449012b14b1e879f40b4a37533e0e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 8 Aug 2014 20:27:01 +0200 Subject: [PATCH 0314/5088] drm/i915: Track cursor changes as frontbuffer tracking flushes We treat other plane updates in the same fashion. Spotted because Rodrigo kept reporting a bug in the PSR code where the frontbuffer was eternally stuck with a dirty cursor bit set. The psr testcase should have caught this, but that i-g-t is kaputt. Rodrigo is signed up to fix that. Cc: Rodrigo Vivi Tested-by-and-Reviewed-by: Rodrigo Vivi 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 fd15601f6360..b2e4eac7b70b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11782,6 +11782,10 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, return intel_crtc_cursor_set_obj(crtc, obj, crtc_w, crtc_h); } else { intel_crtc_update_cursor(crtc, visible); + + intel_frontbuffer_flip(crtc->dev, + INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe)); + return 0; } } -- GitLab From 92561cb7883194714475c7a7775a11a9c40f75cb Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 15 Aug 2014 01:44:32 +0000 Subject: [PATCH 0315/5088] perf probe: Warn user to rebuild target with debuginfo Warn user to rebuild target with debuginfo when the perf probe fails to find debug information in the target binary. Without this, perf probe just reports the failure, but it's no hint for users. This gives more hint for users. Without this: $ strip perf $ ./perf probe -x perf -L argv_split Failed to open debuginfo file. Error: Failed to show lines. With this: $ strip perf $ ./perf probe -x perf -L argv_split The /home/fedora/ksrc/linux-3/tools/perf/perf file has no debug information. Rebuild with -g, or install an appropriate debuginfo package. Error: Failed to show lines. The "rebuild with ..." part changes to "rebuild with CONFIG_DEBUG_INFO" if the target is the kernel or a kernel module. Suggested-by: Arnaldo Carvalho de Melo Signed-off-by: Masami Hiramatsu Cc: Brendan Gregg Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: yrl.pp-manager.tt@hitachi.com Link: http://lkml.kernel.org/r/20140815014432.29869.57941.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 41 ++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 784ea42ad8cb..ac15ff780009 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -258,21 +258,33 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) #ifdef HAVE_DWARF_SUPPORT /* Open new debuginfo of given module */ -static struct debuginfo *open_debuginfo(const char *module) +static struct debuginfo *open_debuginfo(const char *module, bool silent) { const char *path = module; + struct debuginfo *ret; if (!module || !strchr(module, '/')) { path = kernel_get_module_path(module); if (!path) { - pr_err("Failed to find path of %s module.\n", - module ?: "kernel"); + if (!silent) + pr_err("Failed to find path of %s module.\n", + module ?: "kernel"); return NULL; } } - return debuginfo__new(path); + ret = debuginfo__new(path); + if (!ret && !silent) { + pr_warning("The %s file has no debug information.\n", path); + if (!module || !strtailcmp(path, ".ko")) + pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, "); + else + pr_warning("Rebuild with -g, "); + pr_warning("or install an appropriate debuginfo package.\n"); + } + return ret; } + static int get_text_start_address(const char *exec, unsigned long *address) { Elf *elf; @@ -333,15 +345,13 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, pr_debug("try to find information at %" PRIx64 " in %s\n", addr, tp->module ? : "kernel"); - dinfo = open_debuginfo(tp->module); + dinfo = open_debuginfo(tp->module, verbose == 0); if (dinfo) { ret = debuginfo__find_probe_point(dinfo, (unsigned long)addr, pp); debuginfo__delete(dinfo); - } else { - pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr); + } else ret = -ENOENT; - } if (ret > 0) { pp->retprobe = tp->retprobe; @@ -457,13 +467,11 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, struct debuginfo *dinfo; int ntevs, ret = 0; - dinfo = open_debuginfo(target); + dinfo = open_debuginfo(target, !need_dwarf); if (!dinfo) { - if (need_dwarf) { - pr_warning("Failed to open debuginfo file.\n"); + if (need_dwarf) return -ENOENT; - } pr_debug("Could not open debuginfo. Try to use symbols.\n"); return 0; } @@ -620,11 +628,9 @@ static int __show_line_range(struct line_range *lr, const char *module) char *tmp; /* Search a line range */ - dinfo = open_debuginfo(module); - if (!dinfo) { - pr_warning("Failed to open debuginfo file.\n"); + dinfo = open_debuginfo(module, false); + if (!dinfo) return -ENOENT; - } ret = debuginfo__find_line_range(dinfo, lr); debuginfo__delete(dinfo); @@ -772,9 +778,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, if (ret < 0) return ret; - dinfo = open_debuginfo(module); + dinfo = open_debuginfo(module, false); if (!dinfo) { - pr_warning("Failed to open debuginfo file.\n"); ret = -ENOENT; goto out; } -- GitLab From 1e2bb043f171084e5f34816a4268304512d35a46 Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Thu, 14 Aug 2014 14:03:00 -0700 Subject: [PATCH 0316/5088] perf annotate: Don't truncate Intel style addresses Instructions like "mov r9,QWORD PTR [rdx+0x8]" were being truncated to "mov r9,QWORD" by code that assuemd operands cannot have spaces. Signed-off-by: Alex Converse Cc: Adrian Hunter Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1408050180-14088-1-git-send-email-aconverse@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7745fec01a6b..36437527dbb3 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -232,9 +232,16 @@ static int mov__parse(struct ins_operands *ops) return -1; target = ++s; + comment = strchr(s, '#'); - while (s[0] != '\0' && !isspace(s[0])) - ++s; + if (comment != NULL) + s = comment - 1; + else + s = strchr(s, '\0') - 1; + + while (s > target && isspace(s[0])) + --s; + s++; prev = *s; *s = '\0'; @@ -244,7 +251,6 @@ static int mov__parse(struct ins_operands *ops) if (ops->target.raw == NULL) goto out_free_source; - comment = strchr(s, '#'); if (comment == NULL) return 0; -- GitLab From c4d2df495c5bf05661772abf9b88f2696fd810c4 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 14 Aug 2014 12:39:20 -0700 Subject: [PATCH 0317/5088] perf tools: Add arm64 triplets Adds the triplet used for arm64 by Android. Others will want to add their own later. Signed-off-by: Elliott Hughes Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814193920.A7D2D20572@enh.mtv.corp.google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/common.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index 42faf369211c..49776f190abf 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -12,6 +12,11 @@ const char *const arm_triplets[] = { NULL }; +const char *const arm64_triplets[] = { + "aarch64-linux-android-", + NULL +}; + const char *const powerpc_triplets[] = { "powerpc-unknown-linux-gnu-", "powerpc64-unknown-linux-gnu-", @@ -105,6 +110,8 @@ static const char *normalize_arch(char *arch) return "x86"; if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5)) return "sparc"; + if (!strcmp(arch, "aarch64") || !strcmp(arch, "arm64")) + return "arm64"; if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110")) return "arm"; if (!strncmp(arch, "s390", 4)) @@ -159,6 +166,8 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env, if (!strcmp(arch, "arm")) path_list = arm_triplets; + else if (!strcmp(arch, "arm64")) + path_list = arm64_triplets; else if (!strcmp(arch, "powerpc")) path_list = powerpc_triplets; else if (!strcmp(arch, "sh")) -- GitLab From 885b5930d6632fc7df55445d9021b87d8bb17a9b Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Fri, 15 Aug 2014 00:26:14 -0700 Subject: [PATCH 0318/5088] perf tools: Annotate PMU related list_head members with type info So that we can more readily understand in which list heads structs are stored into. Signed-off-by: Cody P Schafer Cc: Andi Kleen Cc: Anshuman Khandual Cc: Cody P Schafer Cc: Haren Myneni Cc: Jiri Olsa Cc: Michael Ellerman Cc: Peter Zijlstra Cc: Stephane Eranian Cc: linuxppc-dev@lists.ozlabs.org Link: http://lkml.kernel.org/r/1408087583-32239-6-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 4 ++-- tools/perf/util/pmu.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 7a811eb61f75..9bf582750561 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -14,8 +14,8 @@ struct perf_pmu_alias { char *name; - struct list_head terms; - struct list_head list; + struct list_head terms; /* HEAD struct parse_events_term -> list */ + struct list_head list; /* ELEM */ char unit[UNIT_MAX_LEN+1]; double scale; }; diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index c14a543ce1f3..1c1e2eecbe1f 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -17,9 +17,9 @@ struct perf_pmu { char *name; __u32 type; struct cpu_map *cpus; - struct list_head format; - struct list_head aliases; - struct list_head list; + struct list_head format; /* HEAD struct perf_pmu_format -> list */ + struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */ + struct list_head list; /* ELEM */ }; struct perf_pmu *perf_pmu__find(const char *name); -- GitLab From e8232f1ad4682c34e7e774c212ccd0c15bb5aa26 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 14 Aug 2014 15:01:38 +0900 Subject: [PATCH 0319/5088] perf report: Relax -g option parsing not to limit the option order Current perf report -g/--call-graph option parser requires for option argument having following order: type,min_percent[,print_limit],order,key But sometimes it's annoying to type all even if one just wants to change the "order" or "key" setting. This patch fixes it to remove the ordering restriction so that one can use just "-g caller", for instance. The only remaining restriction is that the "print_limit" always comes after the "min_percent". Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Arun Sharma Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Rodrigo Campos Link: http://lkml.kernel.org/r/1407996100-6359-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/callchain.c | 95 +++++++++++++++---------------------- 1 file changed, 38 insertions(+), 57 deletions(-) diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 437ee09727e6..08f0fbf5527c 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -28,74 +28,55 @@ __thread struct callchain_cursor callchain_cursor; int parse_callchain_report_opt(const char *arg) { - char *tok, *tok2; + char *tok; char *endptr; + bool minpcnt_set = false; symbol_conf.use_callchain = true; if (!arg) return 0; - tok = strtok((char *)arg, ","); - if (!tok) - return -1; - - /* get the output mode */ - if (!strncmp(tok, "graph", strlen(arg))) { - callchain_param.mode = CHAIN_GRAPH_ABS; - - } else if (!strncmp(tok, "flat", strlen(arg))) { - callchain_param.mode = CHAIN_FLAT; - } else if (!strncmp(tok, "fractal", strlen(arg))) { - callchain_param.mode = CHAIN_GRAPH_REL; - } else if (!strncmp(tok, "none", strlen(arg))) { - callchain_param.mode = CHAIN_NONE; - symbol_conf.use_callchain = false; - return 0; - } else { - return -1; - } - - /* get the min percentage */ - tok = strtok(NULL, ","); - if (!tok) - goto setup; - - callchain_param.min_percent = strtod(tok, &endptr); - if (tok == endptr) - return -1; + while ((tok = strtok((char *)arg, ",")) != NULL) { + if (!strncmp(tok, "none", strlen(tok))) { + callchain_param.mode = CHAIN_NONE; + symbol_conf.use_callchain = false; + return 0; + } - /* get the print limit */ - tok2 = strtok(NULL, ","); - if (!tok2) - goto setup; + /* try to get the output mode */ + if (!strncmp(tok, "graph", strlen(tok))) + callchain_param.mode = CHAIN_GRAPH_ABS; + else if (!strncmp(tok, "flat", strlen(tok))) + callchain_param.mode = CHAIN_FLAT; + else if (!strncmp(tok, "fractal", strlen(tok))) + callchain_param.mode = CHAIN_GRAPH_REL; + /* try to get the call chain order */ + else if (!strncmp(tok, "caller", strlen(tok))) + callchain_param.order = ORDER_CALLER; + else if (!strncmp(tok, "callee", strlen(tok))) + callchain_param.order = ORDER_CALLEE; + /* try to get the sort key */ + else if (!strncmp(tok, "function", strlen(tok))) + callchain_param.key = CCKEY_FUNCTION; + else if (!strncmp(tok, "address", strlen(tok))) + callchain_param.key = CCKEY_ADDRESS; + /* try to get the min percent */ + else if (!minpcnt_set) { + callchain_param.min_percent = strtod(tok, &endptr); + if (tok == endptr) + return -1; + minpcnt_set = true; + } else { + /* try print limit at last */ + callchain_param.print_limit = strtoul(tok, &endptr, 0); + if (tok == endptr) + return -1; + } - if (tok2[0] != 'c') { - callchain_param.print_limit = strtoul(tok2, &endptr, 0); - tok2 = strtok(NULL, ","); - if (!tok2) - goto setup; + arg = NULL; } - /* get the call chain order */ - if (!strncmp(tok2, "caller", strlen("caller"))) - callchain_param.order = ORDER_CALLER; - else if (!strncmp(tok2, "callee", strlen("callee"))) - callchain_param.order = ORDER_CALLEE; - else - return -1; - - /* Get the sort key */ - tok2 = strtok(NULL, ","); - if (!tok2) - goto setup; - if (!strncmp(tok2, "function", strlen("function"))) - callchain_param.key = CCKEY_FUNCTION; - else if (!strncmp(tok2, "address", strlen("address"))) - callchain_param.key = CCKEY_ADDRESS; - else - return -1; -setup: if (callchain_register_param(&callchain_param) < 0) { pr_err("Can't register callchain params\n"); return -1; -- GitLab From 6eb08660962a91212902869672dab5199827cbfd Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:30 +0000 Subject: [PATCH 0320/5088] perf probe: Don't use strerror if strlist__add failed Since the strlist__add doesn't involves any IO, the failure reason must be ENOMEM or EINVAL, moreover this is just a debug message, we don't need to show the error string. And also, if get_probe_trace_command_rawlist() returns NULL, it doesn't mean the rawlist is empty, there is an error. So caller must use -ENOMEM for the error. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022230.3545.99254.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index ac15ff780009..bf39c23b275d 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1881,7 +1881,7 @@ static struct strlist *get_probe_trace_command_rawlist(int fd) p[idx] = '\0'; ret = strlist__add(sl, buf); if (ret < 0) { - pr_debug("strlist__add failed: %s\n", strerror(-ret)); + pr_debug("strlist__add failed (%d)\n", ret); strlist__delete(sl); return NULL; } @@ -1940,7 +1940,7 @@ static int __show_perf_probe_events(int fd, bool is_kprobe) rawlist = get_probe_trace_command_rawlist(fd); if (!rawlist) - return -ENOENT; + return -ENOMEM; strlist__for_each(ent, rawlist) { ret = parse_probe_trace_command(ent->s, &tev); @@ -2007,6 +2007,8 @@ static struct strlist *get_probe_trace_event_names(int fd, bool include_group) memset(&tev, 0, sizeof(tev)); rawlist = get_probe_trace_command_rawlist(fd); + if (!rawlist) + return NULL; sl = strlist__new(true, NULL); strlist__for_each(ent, rawlist) { ret = parse_probe_trace_command(ent->s, &tev); -- GitLab From b2348e1d8a67c58de44820587fabc4f987eafbb6 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:32 +0000 Subject: [PATCH 0321/5088] perf: Use strerror_r instead of strerror Use strerror_r instead of strerror in error messages for thread-safety. This also introduce STRERR_BUFSIZE macro for the default size of message buffer for strerror_r. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022232.3545.14026.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/perf.c | 10 +++++++--- tools/perf/util/debug.h | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 2282d41879a2..452a8474d29d 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -313,6 +313,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) int status; struct stat st; const char *prefix; + char sbuf[STRERR_BUFSIZE]; prefix = NULL; if (p->option & RUN_SETUP) @@ -343,7 +344,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) status = 1; /* Check for ENOSPC and EIO errors.. */ if (fflush(stdout)) { - fprintf(stderr, "write failure on standard output: %s", strerror(errno)); + fprintf(stderr, "write failure on standard output: %s", + strerror_r(errno, sbuf, sizeof(sbuf))); goto out; } if (ferror(stdout)) { @@ -351,7 +353,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) goto out; } if (fclose(stdout)) { - fprintf(stderr, "close failed on standard output: %s", strerror(errno)); + fprintf(stderr, "close failed on standard output: %s", + strerror_r(errno, sbuf, sizeof(sbuf))); goto out; } status = 0; @@ -466,6 +469,7 @@ void pthread__unblock_sigwinch(void) int main(int argc, const char **argv) { const char *cmd; + char sbuf[STRERR_BUFSIZE]; /* The page_size is placed in util object. */ page_size = sysconf(_SC_PAGE_SIZE); @@ -561,7 +565,7 @@ int main(int argc, const char **argv) } fprintf(stderr, "Failed to run command '%s': %s\n", - cmd, strerror(errno)); + cmd, strerror_r(errno, sbuf, sizeof(sbuf))); out: return 1; } diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 6944ea3a119b..be264d6f3b30 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -3,6 +3,7 @@ #define __PERF_DEBUG_H #include +#include #include "event.h" #include "../ui/helpline.h" #include "../ui/progress.h" @@ -36,6 +37,8 @@ extern int debug_ordered_events; #define pr_oe_time(t, fmt, ...) pr_time_N(1, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__) #define pr_oe_time2(t, fmt, ...) pr_time_N(2, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__) +#define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */ + int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void trace_event(union perf_event *event); -- GitLab From 5f03cba41590b5e7db5b66d2b2aa3e146ff8a84f Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:34 +0000 Subject: [PATCH 0322/5088] perf probe: Make error messages thread-safe To make error messages thread-safe, this replaces strerror with strerror_r for warnings, and just shows the return value instead of using strerror for debug messages. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022234.3545.22199.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 5 ++++- tools/perf/util/probe-event.c | 28 +++++++++++++++------------- tools/perf/util/probe-finder.c | 7 +++++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c63fa2925075..347729e29a92 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -290,8 +290,11 @@ static void cleanup_params(void) static void pr_err_with_code(const char *msg, int err) { + char sbuf[STRERR_BUFSIZE]; + pr_err("%s", msg); - pr_debug(" Reason: %s (Code: %d)", strerror(-err), err); + pr_debug(" Reason: %s (Code: %d)", + strerror_r(-err, sbuf, sizeof(sbuf)), err); pr_err("\n"); } diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index bf39c23b275d..f73595fc0627 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -573,7 +573,7 @@ static int get_real_path(const char *raw_path, const char *comp_dir, static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) { - char buf[LINEBUF_SIZE]; + char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE]; const char *color = show_num ? "" : PERF_COLOR_BLUE; const char *prefix = NULL; @@ -593,7 +593,8 @@ static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) return 1; error: if (ferror(fp)) { - pr_warning("File read error: %s\n", strerror(errno)); + pr_warning("File read error: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); return -1; } return 0; @@ -626,6 +627,7 @@ static int __show_line_range(struct line_range *lr, const char *module) FILE *fp; int ret; char *tmp; + char sbuf[STRERR_BUFSIZE]; /* Search a line range */ dinfo = open_debuginfo(module, false); @@ -662,7 +664,7 @@ static int __show_line_range(struct line_range *lr, const char *module) fp = fopen(lr->path, "r"); if (fp == NULL) { pr_warning("Failed to open %s: %s\n", lr->path, - strerror(errno)); + strerror_r(errno, sbuf, sizeof(sbuf))); return -errno; } /* Skip to starting line number */ @@ -1410,8 +1412,7 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) return tmp - buf; error: - pr_debug("Failed to synthesize perf probe argument: %s\n", - strerror(-ret)); + pr_debug("Failed to synthesize perf probe argument: %d\n", ret); return ret; } @@ -1460,8 +1461,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) return buf; error: - pr_debug("Failed to synthesize perf probe point: %s\n", - strerror(-ret)); + pr_debug("Failed to synthesize perf probe point: %d\n", ret); free(buf); return NULL; } @@ -1787,7 +1787,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) static void print_open_warning(int err, bool is_kprobe) { - char sbuf[128]; + char sbuf[STRERR_BUFSIZE]; if (err == -ENOENT) { const char *config; @@ -1817,7 +1817,7 @@ static void print_both_open_warning(int kerr, int uerr) pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS " "or/and CONFIG_UPROBE_EVENTS.\n"); else { - char sbuf[128]; + char sbuf[STRERR_BUFSIZE]; pr_warning("Failed to open kprobe events: %s.\n", strerror_r(-kerr, sbuf, sizeof(sbuf))); pr_warning("Failed to open uprobe events: %s.\n", @@ -2038,6 +2038,7 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev) { int ret = 0; char *buf = synthesize_probe_trace_command(tev); + char sbuf[STRERR_BUFSIZE]; if (!buf) { pr_debug("Failed to synthesize probe trace event.\n"); @@ -2049,7 +2050,7 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev) ret = write(fd, buf, strlen(buf)); if (ret <= 0) pr_warning("Failed to write event: %s\n", - strerror(errno)); + strerror_r(errno, sbuf, sizeof(sbuf))); } free(buf); return ret; @@ -2063,7 +2064,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base, /* Try no suffix */ ret = e_snprintf(buf, len, "%s", base); if (ret < 0) { - pr_debug("snprintf() failed: %s\n", strerror(-ret)); + pr_debug("snprintf() failed: %d\n", ret); return ret; } if (!strlist__has_entry(namelist, buf)) @@ -2079,7 +2080,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base, for (i = 1; i < MAX_EVENT_INDEX; i++) { ret = e_snprintf(buf, len, "%s_%d", base, i); if (ret < 0) { - pr_debug("snprintf() failed: %s\n", strerror(-ret)); + pr_debug("snprintf() failed: %d\n", ret); return ret; } if (!strlist__has_entry(namelist, buf)) @@ -2444,7 +2445,8 @@ static int __del_trace_probe_event(int fd, struct str_node *ent) printf("Removed event: %s\n", ent->s); return 0; error: - pr_warning("Failed to delete event: %s\n", strerror(-ret)); + pr_warning("Failed to delete event: %s\n", + strerror_r(-ret, buf, sizeof(buf))); return ret; } diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index dca9145d704c..9c593561aa71 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -281,6 +281,7 @@ static int convert_variable_type(Dwarf_Die *vr_die, struct probe_trace_arg_ref **ref_ptr = &tvar->ref; Dwarf_Die type; char buf[16]; + char sbuf[STRERR_BUFSIZE]; int bsize, boffs, total; int ret; @@ -367,7 +368,7 @@ static int convert_variable_type(Dwarf_Die *vr_die, if (ret >= 16) ret = -E2BIG; pr_warning("Failed to convert variable type: %s\n", - strerror(-ret)); + strerror_r(-ret, sbuf, sizeof(sbuf))); return ret; } tvar->type = strdup(buf); @@ -779,10 +780,12 @@ static int find_lazy_match_lines(struct intlist *list, size_t line_len; ssize_t len; int count = 0, linenum = 1; + char sbuf[STRERR_BUFSIZE]; fp = fopen(fname, "r"); if (!fp) { - pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); + pr_warning("Failed to open %s: %s\n", fname, + strerror_r(errno, sbuf, sizeof(sbuf))); return -errno; } -- GitLab From 6e81c74cbf4b64620170da14844f1dc8a9a5950f Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:36 +0000 Subject: [PATCH 0323/5088] perf util: Replace strerror with strerror_r for thread-safety Replaces all strerror with strerror_r in util for making the perf lib thread-safe. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022236.3545.3367.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cloexec.c | 6 ++++-- tools/perf/util/data.c | 8 ++++++-- tools/perf/util/dso.c | 8 ++++++-- tools/perf/util/evlist.c | 2 +- tools/perf/util/evsel.c | 7 +++++-- tools/perf/util/parse-events.c | 5 ++++- tools/perf/util/run-command.c | 9 +++++++-- tools/perf/util/util.c | 5 +++-- 8 files changed, 36 insertions(+), 14 deletions(-) diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index 4945aa56a017..47b78b3f0325 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c @@ -3,6 +3,7 @@ #include "../perf.h" #include "cloexec.h" #include "asm/bug.h" +#include "debug.h" static unsigned long flag = PERF_FLAG_FD_CLOEXEC; @@ -18,6 +19,7 @@ static int perf_flag_probe(void) int err; int cpu; pid_t pid = -1; + char sbuf[STRERR_BUFSIZE]; cpu = sched_getcpu(); if (cpu < 0) @@ -42,7 +44,7 @@ static int perf_flag_probe(void) WARN_ONCE(err != EINVAL && err != EBUSY, "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", - err, strerror(err)); + err, strerror_r(err, sbuf, sizeof(sbuf))); /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ fd = sys_perf_event_open(&attr, pid, cpu, -1, 0); @@ -50,7 +52,7 @@ static int perf_flag_probe(void) if (WARN_ONCE(fd < 0 && err != EBUSY, "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", - err, strerror(err))) + err, strerror_r(err, sbuf, sizeof(sbuf)))) return -1; close(fd); diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 29d720cf5844..1921942fc2e0 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c @@ -50,12 +50,14 @@ static int open_file_read(struct perf_data_file *file) { struct stat st; int fd; + char sbuf[STRERR_BUFSIZE]; fd = open(file->path, O_RDONLY); if (fd < 0) { int err = errno; - pr_err("failed to open %s: %s", file->path, strerror(err)); + pr_err("failed to open %s: %s", file->path, + strerror_r(err, sbuf, sizeof(sbuf))); if (err == ENOENT && !strcmp(file->path, "perf.data")) pr_err(" (try 'perf record' first)"); pr_err("\n"); @@ -88,6 +90,7 @@ static int open_file_read(struct perf_data_file *file) static int open_file_write(struct perf_data_file *file) { int fd; + char sbuf[STRERR_BUFSIZE]; if (check_backup(file)) return -1; @@ -95,7 +98,8 @@ static int open_file_write(struct perf_data_file *file) fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR); if (fd < 0) - pr_err("failed to open %s : %s\n", file->path, strerror(errno)); + pr_err("failed to open %s : %s\n", file->path, + strerror_r(errno, sbuf, sizeof(sbuf))); return fd; } diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index bdafd306fb52..55e39dc1bcda 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -162,13 +162,15 @@ static void close_first_dso(void); static int do_open(char *name) { int fd; + char sbuf[STRERR_BUFSIZE]; do { fd = open(name, O_RDONLY); if (fd >= 0) return fd; - pr_debug("dso open failed, mmap: %s\n", strerror(errno)); + pr_debug("dso open failed, mmap: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); if (!dso__data_open_cnt || errno != EMFILE) break; @@ -530,10 +532,12 @@ static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size) static int data_file_size(struct dso *dso) { struct stat st; + char sbuf[STRERR_BUFSIZE]; if (!dso->data.file_size) { if (fstat(dso->data.fd, &st)) { - pr_err("dso mmap failed, fstat: %s\n", strerror(errno)); + pr_err("dso mmap failed, fstat: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); return -1; } dso->data.file_size = st.st_size; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 5dcd28c79c6e..a3e28b49128a 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1295,7 +1295,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, int err, char *buf, size_t size) { int printed, value; - char sbuf[128], *emsg = strerror_r(err, sbuf, sizeof(sbuf)); + char sbuf[STRERR_BUFSIZE], *emsg = strerror_r(err, sbuf, sizeof(sbuf)); switch (err) { case EACCES: diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 01ce14c3575e..b38de5819323 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2027,6 +2027,8 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, int err, char *msg, size_t size) { + char sbuf[STRERR_BUFSIZE]; + switch (err) { case EPERM: case EACCES: @@ -2072,8 +2074,9 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, } return scnprintf(msg, size, - "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n" + "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n" "/bin/dmesg may provide additional information.\n" "No CONFIG_PERF_EVENTS=y kernel support configured?\n", - err, strerror(err), perf_evsel__name(evsel)); + err, strerror_r(err, sbuf, sizeof(sbuf)), + perf_evsel__name(evsel)); } diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1e15df10a88c..e34c81a0bcf3 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -10,6 +10,7 @@ #include "symbol.h" #include "cache.h" #include "header.h" +#include "debug.h" #include #include "parse-events-bison.h" #define YY_EXTRA_TYPE int @@ -1006,9 +1007,11 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; + char sbuf[STRERR_BUFSIZE]; if (debugfs_valid_mountpoint(tracing_events_path)) { - printf(" [ Tracepoints not available: %s ]\n", strerror(errno)); + printf(" [ Tracepoints not available: %s ]\n", + strerror_r(errno, sbuf, sizeof(sbuf))); return; } diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c index da8e9b285f51..34622b53e733 100644 --- a/tools/perf/util/run-command.c +++ b/tools/perf/util/run-command.c @@ -1,6 +1,7 @@ #include "cache.h" #include "run-command.h" #include "exec_cmd.h" +#include "debug.h" static inline void close_pair(int fd[2]) { @@ -19,6 +20,7 @@ int start_command(struct child_process *cmd) { int need_in, need_out, need_err; int fdin[2], fdout[2], fderr[2]; + char sbuf[STRERR_BUFSIZE]; /* * In case of errors we must keep the promise to close FDs @@ -99,7 +101,7 @@ int start_command(struct child_process *cmd) if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], - cmd->dir, strerror(errno)); + cmd->dir, strerror_r(errno, sbuf, sizeof(sbuf))); if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) @@ -153,6 +155,8 @@ int start_command(struct child_process *cmd) static int wait_or_whine(pid_t pid) { + char sbuf[STRERR_BUFSIZE]; + for (;;) { int status, code; pid_t waiting = waitpid(pid, &status, 0); @@ -160,7 +164,8 @@ static int wait_or_whine(pid_t pid) if (waiting < 0) { if (errno == EINTR) continue; - error("waitpid failed (%s)", strerror(errno)); + error("waitpid failed (%s)", + strerror_r(errno, sbuf, sizeof(sbuf))); return -ERR_RUN_COMMAND_WAITPID; } if (waiting != pid) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 25822bdf7bbf..24e8d871b74e 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -456,6 +456,7 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep) size_t size = 0, alloc_size = 0; void *bf = NULL, *nbf; int fd, n, err = 0; + char sbuf[STRERR_BUFSIZE]; fd = open(filename, O_RDONLY); if (fd < 0) @@ -476,8 +477,8 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep) n = read(fd, bf + size, alloc_size - size); if (n < 0) { if (size) { - pr_warning("read failed %d: %s\n", - errno, strerror(errno)); + pr_warning("read failed %d: %s\n", errno, + strerror_r(errno, sbuf, sizeof(sbuf))); err = 0; } else err = -errno; -- GitLab From 809adea685f7dbc9bdcc38b27d24801c461d8413 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:38 +0000 Subject: [PATCH 0324/5088] perf top: Use strerror_r instead of strerror Use strerror_r instead of strerror in error message for thread-safety. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022238.3545.15569.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 87a6615a40fa..a77ff6ca5fbd 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -899,7 +899,7 @@ static int perf_top__start_counters(struct perf_top *top) if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { ui__error("Failed to mmap with %d (%s)\n", - errno, strerror(errno)); + errno, strerror_r(errno, msg, sizeof(msg))); goto out_err; } -- GitLab From 942a91ed3ffff0267944ed3161ae292d0960fd44 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:41 +0000 Subject: [PATCH 0325/5088] perf trace: Use strerror_r instead of strerror Use strerror_r instead of strerror in error message for thead-safety. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022241.3545.97543.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d080b9cf0354..a9e96ff49c7f 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1750,7 +1750,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, signed_print: fprintf(trace->output, ") = %d", ret); } else if (ret < 0 && sc->fmt->errmsg) { - char bf[256]; + char bf[STRERR_BUFSIZE]; const char *emsg = strerror_r(-ret, bf, sizeof(bf)), *e = audit_errno_to_name(-ret); @@ -2044,6 +2044,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) int err = -1, i; unsigned long before; const bool forks = argc > 0; + char sbuf[STRERR_BUFSIZE]; trace->live = true; @@ -2105,7 +2106,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv) err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); if (err < 0) { - fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); + fprintf(trace->output, "Couldn't mmap the events: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } -- GitLab From 35550da389ba8752f024a44ef14b74001c4fc4d3 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:43 +0000 Subject: [PATCH 0326/5088] perf record: Use strerror_r instead of strerror Use strerror_r instead of strerror in error messages for thread-safety. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022243.3545.7411.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4db670d4b8da..87e28a4e33ba 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -161,7 +161,7 @@ static int record__open(struct record *rec) if (perf_evlist__apply_filters(evlist)) { error("failed to set filter with %d (%s)\n", errno, - strerror(errno)); + strerror_r(errno, msg, sizeof(msg))); rc = -1; goto out; } @@ -175,7 +175,8 @@ static int record__open(struct record *rec) "(current value: %u)\n", opts->mmap_pages); rc = -errno; } else { - pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); + pr_err("failed to mmap with %d (%s)\n", errno, + strerror_r(errno, msg, sizeof(msg))); rc = -errno; } goto out; @@ -480,7 +481,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } if (forks && workload_exec_errno) { - char msg[512]; + char msg[STRERR_BUFSIZE]; const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); pr_err("Workload failed: %s\n", emsg); err = -1; -- GitLab From ba3dfff8ad2d98df0c8116faaeb281c93e161636 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:45 +0000 Subject: [PATCH 0327/5088] perf test: Use strerror_r instead of strerror Use strerror_r instead of strerror in error messages for thread-safety. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022245.3545.91394.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/builtin-test.c | 4 +++- tools/perf/tests/mmap-basic.c | 7 ++++--- tools/perf/tests/open-syscall-all-cpus.c | 5 +++-- tools/perf/tests/open-syscall-tp-fields.c | 7 +++++-- tools/perf/tests/open-syscall.c | 3 ++- tools/perf/tests/perf-record.c | 13 +++++++++---- tools/perf/tests/rdpmc.c | 6 ++++-- tools/perf/tests/sw-clock.c | 6 ++++-- tools/perf/tests/task-exit.c | 6 ++++-- 9 files changed, 38 insertions(+), 19 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index c6796d22423a..99481361b19f 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -185,9 +185,11 @@ static bool perf_test__matches(int curr, int argc, const char *argv[]) static int run_test(struct test *test) { int status, err = -1, child = fork(); + char sbuf[STRERR_BUFSIZE]; if (child < 0) { - pr_err("failed to fork test: %s\n", strerror(errno)); + pr_err("failed to fork test: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); return -1; } diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 142263492f6f..9b9622a33932 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -31,6 +31,7 @@ int test__basic_mmap(void) unsigned int nr_events[nsyscalls], expected_nr_events[nsyscalls], i, j; struct perf_evsel *evsels[nsyscalls], *evsel; + char sbuf[STRERR_BUFSIZE]; threads = thread_map__new(-1, getpid(), UINT_MAX); if (threads == NULL) { @@ -49,7 +50,7 @@ int test__basic_mmap(void) sched_setaffinity(0, sizeof(cpu_set), &cpu_set); if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { pr_debug("sched_setaffinity() failed on CPU %d: %s ", - cpus->map[0], strerror(errno)); + cpus->map[0], strerror_r(errno, sbuf, sizeof(sbuf))); goto out_free_cpus; } @@ -79,7 +80,7 @@ int test__basic_mmap(void) if (perf_evsel__open(evsels[i], cpus, threads) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", - strerror(errno)); + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -89,7 +90,7 @@ int test__basic_mmap(void) if (perf_evlist__mmap(evlist, 128, true) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, - strerror(errno)); + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c index 5fecdbd2f5f7..8fa82d1700c7 100644 --- a/tools/perf/tests/open-syscall-all-cpus.c +++ b/tools/perf/tests/open-syscall-all-cpus.c @@ -12,6 +12,7 @@ int test__open_syscall_event_on_all_cpus(void) unsigned int nr_open_calls = 111, i; cpu_set_t cpu_set; struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); + char sbuf[STRERR_BUFSIZE]; if (threads == NULL) { pr_debug("thread_map__new\n"); @@ -35,7 +36,7 @@ int test__open_syscall_event_on_all_cpus(void) if (perf_evsel__open(evsel, cpus, threads) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", - strerror(errno)); + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_evsel_delete; } @@ -56,7 +57,7 @@ int test__open_syscall_event_on_all_cpus(void) if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { pr_debug("sched_setaffinity() failed on CPU %d: %s ", cpus->map[cpu], - strerror(errno)); + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_close_fd; } for (i = 0; i < ncalls; ++i) { diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c index 0785b64ffd6c..922bdb627950 100644 --- a/tools/perf/tests/open-syscall-tp-fields.c +++ b/tools/perf/tests/open-syscall-tp-fields.c @@ -22,6 +22,7 @@ int test__syscall_open_tp_fields(void) struct perf_evlist *evlist = perf_evlist__new(); struct perf_evsel *evsel; int err = -1, i, nr_events = 0, nr_polls = 0; + char sbuf[STRERR_BUFSIZE]; if (evlist == NULL) { pr_debug("%s: perf_evlist__new\n", __func__); @@ -48,13 +49,15 @@ int test__syscall_open_tp_fields(void) err = perf_evlist__open(evlist); if (err < 0) { - pr_debug("perf_evlist__open: %s\n", strerror(errno)); + pr_debug("perf_evlist__open: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } err = perf_evlist__mmap(evlist, UINT_MAX, false); if (err < 0) { - pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); + pr_debug("perf_evlist__mmap: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c index c1dc7d25f38c..a33b2daae40f 100644 --- a/tools/perf/tests/open-syscall.c +++ b/tools/perf/tests/open-syscall.c @@ -9,6 +9,7 @@ int test__open_syscall_event(void) struct perf_evsel *evsel; unsigned int nr_open_calls = 111, i; struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); + char sbuf[STRERR_BUFSIZE]; if (threads == NULL) { pr_debug("thread_map__new\n"); @@ -24,7 +25,7 @@ int test__open_syscall_event(void) if (perf_evsel__open_per_thread(evsel, threads) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", - strerror(errno)); + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_evsel_delete; } diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index aca1a83dd13a..2ce753c1db63 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -59,6 +59,7 @@ int test__PERF_RECORD(void) int err = -1, errs = 0, i, wakeups = 0; u32 cpu; int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; + char sbuf[STRERR_BUFSIZE]; if (evlist == NULL || argv == NULL) { pr_debug("Not enough memory to create evlist\n"); @@ -100,7 +101,8 @@ int test__PERF_RECORD(void) err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); if (err < 0) { - pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); + pr_debug("sched__get_first_possible_cpu: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -110,7 +112,8 @@ int test__PERF_RECORD(void) * So that we can check perf_sample.cpu on all the samples. */ if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { - pr_debug("sched_setaffinity: %s\n", strerror(errno)); + pr_debug("sched_setaffinity: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -120,7 +123,8 @@ int test__PERF_RECORD(void) */ err = perf_evlist__open(evlist); if (err < 0) { - pr_debug("perf_evlist__open: %s\n", strerror(errno)); + pr_debug("perf_evlist__open: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -131,7 +135,8 @@ int test__PERF_RECORD(void) */ err = perf_evlist__mmap(evlist, opts.mmap_pages, false); if (err < 0) { - pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); + pr_debug("perf_evlist__mmap: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c index c04d1f268576..d31f2c4d9f64 100644 --- a/tools/perf/tests/rdpmc.c +++ b/tools/perf/tests/rdpmc.c @@ -100,6 +100,7 @@ static int __test__rdpmc(void) }; u64 delta_sum = 0; struct sigaction sa; + char sbuf[STRERR_BUFSIZE]; sigfillset(&sa.sa_mask); sa.sa_sigaction = segfault_handler; @@ -109,14 +110,15 @@ static int __test__rdpmc(void) perf_event_open_cloexec_flag()); if (fd < 0) { pr_err("Error: sys_perf_event_open() syscall returned " - "with %d (%s)\n", fd, strerror(errno)); + "with %d (%s)\n", fd, + strerror_r(errno, sbuf, sizeof(sbuf))); return -1; } addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); if (addr == (void *)(-1)) { pr_err("Error: mmap() syscall returned with (%s)\n", - strerror(errno)); + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_close; } diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index 983d6b8562a8..1aa21c90731b 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c @@ -22,6 +22,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) volatile int tmp = 0; u64 total_periods = 0; int nr_samples = 0; + char sbuf[STRERR_BUFSIZE]; union perf_event *event; struct perf_evsel *evsel; struct perf_evlist *evlist; @@ -62,14 +63,15 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) err = -errno; pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", - strerror(errno), knob, (u64)attr.sample_freq); + strerror_r(errno, sbuf, sizeof(sbuf)), + knob, (u64)attr.sample_freq); goto out_delete_evlist; } err = perf_evlist__mmap(evlist, 128, true); if (err < 0) { pr_debug("failed to mmap event: %d (%s)\n", errno, - strerror(errno)); + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index 5ff3db318f12..87522f01c7ad 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -42,6 +42,7 @@ int test__task_exit(void) .uses_mmap = true, }; const char *argv[] = { "true", NULL }; + char sbuf[STRERR_BUFSIZE]; signal(SIGCHLD, sig_handler); @@ -82,13 +83,14 @@ int test__task_exit(void) err = perf_evlist__open(evlist); if (err < 0) { - pr_debug("Couldn't open the evlist: %s\n", strerror(-err)); + pr_debug("Couldn't open the evlist: %s\n", + strerror_r(-err, sbuf, sizeof(sbuf))); goto out_delete_evlist; } if (perf_evlist__mmap(evlist, 128, true) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, - strerror(errno)); + strerror_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } -- GitLab From fb74fbda42dc5bcbd9bae5d75bfb6755948db21d Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:47 +0000 Subject: [PATCH 0328/5088] perf sched: Use strerror_r instead of strerror Use strerror_r instead of strerror in error message for thread-safety. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022247.3545.4564.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index f5874a27b346..9c9287fbf8e9 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -428,6 +428,7 @@ static u64 get_cpu_usage_nsec_parent(void) static int self_open_counters(void) { struct perf_event_attr attr; + char sbuf[STRERR_BUFSIZE]; int fd; memset(&attr, 0, sizeof(attr)); @@ -440,7 +441,8 @@ static int self_open_counters(void) if (fd < 0) pr_err("Error: sys_perf_event_open() syscall returned " - "with %d (%s)\n", fd, strerror(errno)); + "with %d (%s)\n", fd, + strerror_r(errno, sbuf, sizeof(sbuf))); return fd; } -- GitLab From 340481ada1af9322d99e9c1ba874391f53ff4fce Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:49 +0000 Subject: [PATCH 0329/5088] perf buildid-cache: Use strerror_r instead of strerror Use strerror_r instead of strerror in error messages for thread-safety. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022249.3545.53211.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-buildid-cache.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index ac5838e0b1bd..70385756da63 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -291,6 +291,7 @@ int cmd_buildid_cache(int argc, const char **argv, *missing_filename = NULL, *update_name_list_str = NULL, *kcore_filename; + char sbuf[STRERR_BUFSIZE]; struct perf_data_file file = { .mode = PERF_DATA_MODE_READ, @@ -347,7 +348,7 @@ int cmd_buildid_cache(int argc, const char **argv, continue; } pr_warning("Couldn't add %s: %s\n", - pos->s, strerror(errno)); + pos->s, strerror_r(errno, sbuf, sizeof(sbuf))); } strlist__delete(list); @@ -365,7 +366,7 @@ int cmd_buildid_cache(int argc, const char **argv, continue; } pr_warning("Couldn't remove %s: %s\n", - pos->s, strerror(errno)); + pos->s, strerror_r(errno, sbuf, sizeof(sbuf))); } strlist__delete(list); @@ -386,7 +387,7 @@ int cmd_buildid_cache(int argc, const char **argv, continue; } pr_warning("Couldn't update %s: %s\n", - pos->s, strerror(errno)); + pos->s, strerror_r(errno, sbuf, sizeof(sbuf))); } strlist__delete(list); -- GitLab From f9f33fdba159a9c163ecf1dc0106ebd4c2498130 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:51 +0000 Subject: [PATCH 0330/5088] perf kvm: Use strerror_r instead of strerror Use strerror_r instead of strerror in error messages for thread-safety. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022251.3545.83718.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 14d03edc81c2..1a4ef9cd9d5f 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -990,6 +990,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) int err, rc = -1; struct perf_evsel *pos; struct perf_evlist *evlist = kvm->evlist; + char sbuf[STRERR_BUFSIZE]; perf_evlist__config(evlist, &kvm->opts); @@ -1026,12 +1027,14 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) err = perf_evlist__open(evlist); if (err < 0) { - printf("Couldn't create the events: %s\n", strerror(errno)); + printf("Couldn't create the events: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); goto out; } if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) { - ui__error("Failed to mmap the events: %s\n", strerror(errno)); + ui__error("Failed to mmap the events: %s\n", + strerror_r(errno, sbuf, sizeof(sbuf))); perf_evlist__close(evlist); goto out; } -- GitLab From ede395d27c60c06a2173e7a9c0f4a929a1fef73e Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:53 +0000 Subject: [PATCH 0331/5088] perf help: Use strerror_r instead of strerror Use strerror_r instead of strerror in error messages for thread-safety. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022253.3545.82136.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-help.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 0384d930480b..25d20628212e 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -103,6 +103,8 @@ static int check_emacsclient_version(void) static void exec_woman_emacs(const char *path, const char *page) { + char sbuf[STRERR_BUFSIZE]; + if (!check_emacsclient_version()) { /* This works only with emacsclient version >= 22. */ struct strbuf man_page = STRBUF_INIT; @@ -111,16 +113,19 @@ static void exec_woman_emacs(const char *path, const char *page) path = "emacsclient"; strbuf_addf(&man_page, "(woman \"%s\")", page); execlp(path, "emacsclient", "-e", man_page.buf, NULL); - warning("failed to exec '%s': %s", path, strerror(errno)); + warning("failed to exec '%s': %s", path, + strerror_r(errno, sbuf, sizeof(sbuf))); } } static void exec_man_konqueror(const char *path, const char *page) { const char *display = getenv("DISPLAY"); + if (display && *display) { struct strbuf man_page = STRBUF_INIT; const char *filename = "kfmclient"; + char sbuf[STRERR_BUFSIZE]; /* It's simpler to launch konqueror using kfmclient. */ if (path) { @@ -139,24 +144,31 @@ static void exec_man_konqueror(const char *path, const char *page) path = "kfmclient"; strbuf_addf(&man_page, "man:%s(1)", page); execlp(path, filename, "newTab", man_page.buf, NULL); - warning("failed to exec '%s': %s", path, strerror(errno)); + warning("failed to exec '%s': %s", path, + strerror_r(errno, sbuf, sizeof(sbuf))); } } static void exec_man_man(const char *path, const char *page) { + char sbuf[STRERR_BUFSIZE]; + if (!path) path = "man"; execlp(path, "man", page, NULL); - warning("failed to exec '%s': %s", path, strerror(errno)); + warning("failed to exec '%s': %s", path, + strerror_r(errno, sbuf, sizeof(sbuf))); } static void exec_man_cmd(const char *cmd, const char *page) { struct strbuf shell_cmd = STRBUF_INIT; + char sbuf[STRERR_BUFSIZE]; + strbuf_addf(&shell_cmd, "%s %s", cmd, page); execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL); - warning("failed to exec '%s': %s", cmd, strerror(errno)); + warning("failed to exec '%s': %s", cmd, + strerror_r(errno, sbuf, sizeof(sbuf))); } static void add_man_viewer(const char *name) -- GitLab From 759e612bf96627b64fcafe4174b3f6f2dedf2c0d Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 14 Aug 2014 02:22:55 +0000 Subject: [PATCH 0332/5088] perf stat: Use strerror_r instead of strerror Use strerror_r instead of strerror in error message for thread-safety. Signed-off-by: Masami Hiramatsu Cc: Ingo Molnar Cc: Namhyung Kim Cc: Naohiro Aota Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20140814022255.3545.81549.stgit@kbuild-fedora.novalocal Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 3e80aa10cfd8..5fe0edb1de5d 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -593,7 +593,7 @@ static int __run_perf_stat(int argc, const char **argv) if (perf_evlist__apply_filters(evsel_list)) { error("failed to set filter with %d (%s)\n", errno, - strerror(errno)); + strerror_r(errno, msg, sizeof(msg))); return -1; } -- GitLab From 515d9b2c03943ca904cd135e1b1d9ddd168c1b27 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 12 Aug 2014 18:22:27 +0200 Subject: [PATCH 0333/5088] ata: remove deprecated struct ahci_platform_data The last user of the deprecated struct ahci_platform_data has been cleaned up recently (SPEAr1340 got a proper PHY driver). Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Hans de Goede Signed-off-by: Tejun Heo --- drivers/ata/ahci_platform.c | 18 +----------------- drivers/ata/libahci_platform.c | 23 ----------------------- include/linux/ahci_platform.h | 13 ------------- 3 files changed, 1 insertion(+), 53 deletions(-) diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index f61ddb9146d6..06f1d59fa678 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -32,7 +32,6 @@ static const struct ata_port_info ahci_port_info = { static int ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ahci_host_priv *hpriv; int rc; @@ -44,29 +43,14 @@ static int ahci_probe(struct platform_device *pdev) if (rc) return rc; - /* - * Some platforms might need to prepare for mmio region access, - * which could be done in the following init call. So, the mmio - * region shouldn't be accessed before init (if provided) has - * returned successfully. - */ - if (pdata && pdata->init) { - rc = pdata->init(dev, hpriv->mmio); - if (rc) - goto disable_resources; - } - if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci")) hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ; rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info); if (rc) - goto pdata_exit; + goto disable_resources; return 0; -pdata_exit: - if (pdata && pdata->exit) - pdata->exit(dev); disable_resources: ahci_platform_disable_resources(hpriv); return rc; diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 5b92c290e6c6..c0510de8a4c9 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -502,13 +502,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_init_host); static void ahci_host_stop(struct ata_host *host) { - struct device *dev = host->dev; - struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ahci_host_priv *hpriv = host->private_data; - if (pdata && pdata->exit) - pdata->exit(dev); - ahci_platform_disable_resources(hpriv); } @@ -592,7 +587,6 @@ EXPORT_SYMBOL_GPL(ahci_platform_resume_host); */ int ahci_platform_suspend(struct device *dev) { - struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ata_host *host = dev_get_drvdata(dev); struct ahci_host_priv *hpriv = host->private_data; int rc; @@ -601,19 +595,9 @@ int ahci_platform_suspend(struct device *dev) if (rc) return rc; - if (pdata && pdata->suspend) { - rc = pdata->suspend(dev); - if (rc) - goto resume_host; - } - ahci_platform_disable_resources(hpriv); return 0; - -resume_host: - ahci_platform_resume_host(dev); - return rc; } EXPORT_SYMBOL_GPL(ahci_platform_suspend); @@ -629,7 +613,6 @@ EXPORT_SYMBOL_GPL(ahci_platform_suspend); */ int ahci_platform_resume(struct device *dev) { - struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ata_host *host = dev_get_drvdata(dev); struct ahci_host_priv *hpriv = host->private_data; int rc; @@ -638,12 +621,6 @@ int ahci_platform_resume(struct device *dev) if (rc) return rc; - if (pdata && pdata->resume) { - rc = pdata->resume(dev); - if (rc) - goto disable_resources; - } - rc = ahci_platform_resume_host(dev); if (rc) goto disable_resources; diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h index 09a947e8bc87..642d6ae4030c 100644 --- a/include/linux/ahci_platform.h +++ b/include/linux/ahci_platform.h @@ -22,19 +22,6 @@ struct ata_port_info; struct ahci_host_priv; struct platform_device; -/* - * Note ahci_platform_data is deprecated, it is only kept around for use - * by the old da850 and spear13xx ahci code. - * New drivers should instead declare their own platform_driver struct, and - * use ahci_platform* functions in their own probe, suspend and resume methods. - */ -struct ahci_platform_data { - int (*init)(struct device *dev, void __iomem *addr); - void (*exit)(struct device *dev); - int (*suspend)(struct device *dev); - int (*resume)(struct device *dev); -}; - int ahci_platform_enable_clks(struct ahci_host_priv *hpriv); void ahci_platform_disable_clks(struct ahci_host_priv *hpriv); int ahci_platform_enable_resources(struct ahci_host_priv *hpriv); -- GitLab From 8ad9f9efcc7656cafb56bbbcd545f817a742bf32 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 16 Jun 2014 16:33:46 +0200 Subject: [PATCH 0334/5088] ASoC: Drop const from struct snd_soc_dai_link *of_node members MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dropping the const qualifiers prevents "passing argument 1 of ‘of_node_put’ discards ‘const’ qualifier from pointer target type" type warnings when compiling the code dropping reference to cpu_of_node, codec_of_node or platform_of_node with with an of_node_put() function call. This lets us to avoid casting to struct device_node * or caching variables internally in drivers just to be able to properly drop a reference to the OF node on clean up paths. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- include/sound/soc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index be6ecae247b0..fd58371c63ff 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -897,7 +897,7 @@ struct snd_soc_dai_link { * only for codec to codec links, or systems using device tree. */ const char *cpu_name; - const struct device_node *cpu_of_node; + struct device_node *cpu_of_node; /* * You MAY specify the DAI name of the CPU DAI. If this information is * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node @@ -909,7 +909,7 @@ struct snd_soc_dai_link { * DT/OF node, but not both. */ const char *codec_name; - const struct device_node *codec_of_node; + struct device_node *codec_of_node; /* You MUST specify the DAI name within the codec */ const char *codec_dai_name; @@ -922,7 +922,7 @@ struct snd_soc_dai_link { * do not need a platform. */ const char *platform_name; - const struct device_node *platform_of_node; + struct device_node *platform_of_node; int be_id; /* optional ID for machine driver BE identification */ const struct snd_soc_pcm_stream *params; -- GitLab From eef5bb2445ca49911c93c08ed0fb2ea7363ea945 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Mon, 4 Aug 2014 15:11:16 -0500 Subject: [PATCH 0335/5088] ASoC: cs35l32: Add support for CS35L32 Boosted Amplifier This patch adds support for the Cirrus Logic CS35L32 Boosted Amplifier I2S output provides monitor data to the SOC/CODEC/DSP for speaker protection/enhancement algorithms Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- include/dt-bindings/sound/cs35l32.h | 26 ++ sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs35l32.c | 647 ++++++++++++++++++++++++++++ sound/soc/codecs/cs35l32.h | 93 ++++ 5 files changed, 773 insertions(+) create mode 100644 include/dt-bindings/sound/cs35l32.h create mode 100644 sound/soc/codecs/cs35l32.c create mode 100644 sound/soc/codecs/cs35l32.h diff --git a/include/dt-bindings/sound/cs35l32.h b/include/dt-bindings/sound/cs35l32.h new file mode 100644 index 000000000000..0c6d6a3c15a2 --- /dev/null +++ b/include/dt-bindings/sound/cs35l32.h @@ -0,0 +1,26 @@ +#ifndef __DT_CS35L32_H +#define __DT_CS35L32_H + +#define CS35L32_BOOST_MGR_AUTO 0 +#define CS35L32_BOOST_MGR_AUTO_AUDIO 1 +#define CS35L32_BOOST_MGR_BYPASS 2 +#define CS35L32_BOOST_MGR_FIXED 3 + +#define CS35L32_DATA_CFG_LR_VP 0 +#define CS35L32_DATA_CFG_LR_STAT 1 +#define CS35L32_DATA_CFG_LR 2 +#define CS35L32_DATA_CFG_LR_VPSTAT 3 + +#define CS35L32_BATT_THRESH_3_1V 0 +#define CS35L32_BATT_THRESH_3_2V 1 +#define CS35L32_BATT_THRESH_3_3V 2 +#define CS35L32_BATT_THRESH_3_4V 3 + +#define CS35L32_BATT_RECOV_3_1V 0 +#define CS35L32_BATT_RECOV_3_2V 1 +#define CS35L32_BATT_RECOV_3_3V 2 +#define CS35L32_BATT_RECOV_3_4V 3 +#define CS35L32_BATT_RECOV_3_5V 4 +#define CS35L32_BATT_RECOV_3_6V 5 + +#endif /* __DT_CS35L32_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..77e5383b4361 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ALC5623 if I2C select SND_SOC_ALC5632 if I2C select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC + select SND_SOC_CS35L32 if I2C select SND_SOC_CS42L51_I2C if I2C select SND_SOC_CS42L52 if I2C && INPUT select SND_SOC_CS42L56 if I2C && INPUT @@ -323,6 +324,10 @@ config SND_SOC_ALC5632 config SND_SOC_CQ0093VC tristate +config SND_SOC_CS35L32 + tristate "Cirrus Logic CS35L32 CODEC" + depends on I2C + config SND_SOC_CS42L51 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 20afe0f0c5be..1dacefbdac3c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -32,6 +32,7 @@ snd-soc-ak4671-objs := ak4671.o snd-soc-ak5386-objs := ak5386.o snd-soc-arizona-objs := arizona.o snd-soc-cq93vc-objs := cq93vc.o +snd-soc-cs35l32-objs := cs35l32.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o @@ -203,6 +204,7 @@ obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o +obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c new file mode 100644 index 000000000000..90565d59def7 --- /dev/null +++ b/sound/soc/codecs/cs35l32.c @@ -0,0 +1,647 @@ +/* + * cs35l32.c -- CS35L32 ALSA SoC audio driver + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Brian Austin + * + * 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 +#include +#include + +#include "cs35l32.h" + +#define CS35L32_NUM_SUPPLIES 2 +static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = { + "VA", + "VP", +}; + +struct cs35l32_private { + struct regmap *regmap; + struct snd_soc_codec *codec; + struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES]; + struct cs35l32_platform_data pdata; + struct gpio_desc *reset_gpio; +}; + +static const struct reg_default cs35l32_reg_defaults[] = { + + { 0x06, 0x04 }, /* Power Ctl 1 */ + { 0x07, 0xE8 }, /* Power Ctl 2 */ + { 0x08, 0x40 }, /* Clock Ctl */ + { 0x09, 0x20 }, /* Low Battery Threshold */ + { 0x0A, 0x00 }, /* Voltage Monitor [RO] */ + { 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */ + { 0x0C, 0x07 }, /* IMON Scaling */ + { 0x0D, 0x03 }, /* Audio/LED Pwr Manager */ + { 0x0F, 0x20 }, /* Serial Port Control */ + { 0x10, 0x14 }, /* Class D Amp CTL */ + { 0x11, 0x00 }, /* Protection Release CTL */ + { 0x12, 0xFF }, /* Interrupt Mask 1 */ + { 0x13, 0xFF }, /* Interrupt Mask 2 */ + { 0x14, 0xFF }, /* Interrupt Mask 3 */ + { 0x19, 0x00 }, /* LED Flash Mode Current */ + { 0x1A, 0x00 }, /* LED Movie Mode Current */ + { 0x1B, 0x20 }, /* LED Flash Timer */ + { 0x1C, 0x00 }, /* LED Flash Inhibit Current */ +}; + +static bool cs35l32_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L32_DEVID_AB: + case CS35L32_DEVID_CD: + case CS35L32_DEVID_E: + case CS35L32_FAB_ID: + case CS35L32_REV_ID: + case CS35L32_PWRCTL1: + case CS35L32_PWRCTL2: + case CS35L32_CLK_CTL: + case CS35L32_BATT_THRESHOLD: + case CS35L32_VMON: + case CS35L32_BST_CPCP_CTL: + case CS35L32_IMON_SCALING: + case CS35L32_AUDIO_LED_MNGR: + case CS35L32_ADSP_CTL: + case CS35L32_CLASSD_CTL: + case CS35L32_PROTECT_CTL: + case CS35L32_INT_MASK_1: + case CS35L32_INT_MASK_2: + case CS35L32_INT_MASK_3: + case CS35L32_INT_STATUS_1: + case CS35L32_INT_STATUS_2: + case CS35L32_INT_STATUS_3: + case CS35L32_LED_STATUS: + case CS35L32_FLASH_MODE: + case CS35L32_MOVIE_MODE: + case CS35L32_FLASH_TIMER: + case CS35L32_FLASH_INHIBIT: + return true; + default: + return false; + } +} + +static bool cs35l32_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L32_DEVID_AB: + case CS35L32_DEVID_CD: + case CS35L32_DEVID_E: + case CS35L32_FAB_ID: + case CS35L32_REV_ID: + case CS35L32_INT_STATUS_1: + case CS35L32_INT_STATUS_2: + case CS35L32_INT_STATUS_3: + case CS35L32_LED_STATUS: + return 1; + default: + return 0; + } +} + +static bool cs35l32_precious_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L32_INT_STATUS_1: + case CS35L32_INT_STATUS_2: + case CS35L32_INT_STATUS_3: + case CS35L32_LED_STATUS: + return 1; + default: + return 0; + } +} + +static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0); + +static const struct snd_kcontrol_new imon_ctl = + SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1); + +static const struct snd_kcontrol_new vmon_ctl = + SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1); + +static const struct snd_kcontrol_new vpmon_ctl = + SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1); + +static const struct snd_kcontrol_new cs35l32_snd_controls[] = { + SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL, + 3, 0x04, 1, classd_ctl_tlv), + SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0), + SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0), +}; + +static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = { + + SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0), + SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0), + + SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1), + + SND_SOC_DAPM_INPUT("VP"), + SND_SOC_DAPM_INPUT("ISENSE"), + SND_SOC_DAPM_INPUT("VSENSE"), + + SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl), + SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl), + SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl), +}; + +static const struct snd_soc_dapm_route cs35l32_audio_map[] = { + + {"Speaker", NULL, "BOOST"}, + + {"VMON ADC", NULL, "VSENSE"}, + {"IMON ADC", NULL, "ISENSE"}, + {"VPMON ADC", NULL, "VP"}, + + {"SDOUT", "Switch", "VMON ADC"}, + {"SDOUT", "Switch", "IMON ADC"}, + {"SDOUT", "Switch", "VPMON ADC"}, + + {"Capture", NULL, "SDOUT"}, +}; + +static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + snd_soc_update_bits(codec, CS35L32_ADSP_CTL, + CS35L32_ADSP_MASTER_MASK, + CS35L32_ADSP_MASTER_MASK); + break; + case SND_SOC_DAIFMT_CBS_CFS: + snd_soc_update_bits(codec, CS35L32_ADSP_CTL, + CS35L32_ADSP_MASTER_MASK, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + struct snd_soc_codec *codec = dai->codec; + + return snd_soc_update_bits(codec, CS35L32_PWRCTL2, + CS35L32_SDOUT_3ST, tristate << 3); +} + +static const struct snd_soc_dai_ops cs35l32_ops = { + .set_fmt = cs35l32_set_dai_fmt, + .set_tristate = cs35l32_set_tristate, +}; + +static struct snd_soc_dai_driver cs35l32_dai[] = { + { + .name = "cs35l32-monitor", + .id = 0, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = CS35L32_RATES, + .formats = CS35L32_FORMATS, + }, + .ops = &cs35l32_ops, + .symmetric_rates = 1, + } +}; + +static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec, + int clk_id, int source, unsigned int freq, int dir) +{ + + switch (freq) { + case 6000000: + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK, 0); + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_RATIO_MASK, + CS35L32_MCLK_RATIO); + break; + case 12000000: + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK, + CS35L32_MCLK_DIV2_MASK); + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_RATIO_MASK, + CS35L32_MCLK_RATIO); + break; + case 6144000: + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK, 0); + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_RATIO_MASK, 0); + break; + case 12288000: + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK, + CS35L32_MCLK_DIV2_MASK); + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_RATIO_MASK, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { + .set_sysclk = cs35l32_codec_set_sysclk, + + .dapm_widgets = cs35l32_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets), + .dapm_routes = cs35l32_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map), + + .controls = cs35l32_snd_controls, + .num_controls = ARRAY_SIZE(cs35l32_snd_controls), +}; + +/* Current and threshold powerup sequence Pg37 in datasheet */ +static const struct reg_default cs35l32_monitor_patch[] = { + + { 0x00, 0x99 }, + { 0x48, 0x17 }, + { 0x49, 0x56 }, + { 0x43, 0x01 }, + { 0x3B, 0x62 }, + { 0x3C, 0x80 }, + { 0x00, 0x00 }, +}; + +static struct regmap_config cs35l32_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS35L32_MAX_REGISTER, + .reg_defaults = cs35l32_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults), + .volatile_reg = cs35l32_volatile_register, + .readable_reg = cs35l32_readable_register, + .precious_reg = cs35l32_precious_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int cs35l32_handle_of_data(struct i2c_client *i2c_client, + struct cs35l32_platform_data *pdata) +{ + struct device_node *np = i2c_client->dev.of_node; + unsigned int val; + + if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0) + pdata->sdout_share = val; + + of_property_read_u32(np, "cirrus,boost-manager", &val); + switch (val) { + case CS35L32_BOOST_MGR_AUTO: + case CS35L32_BOOST_MGR_AUTO_AUDIO: + case CS35L32_BOOST_MGR_BYPASS: + case CS35L32_BOOST_MGR_FIXED: + pdata->boost_mng = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,boost-manager DT value %d\n", val); + pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS; + } + + of_property_read_u32(np, "cirrus,sdout-datacfg", &val); + switch (val) { + case CS35L32_DATA_CFG_LR_VP: + case CS35L32_DATA_CFG_LR_STAT: + case CS35L32_DATA_CFG_LR: + case CS35L32_DATA_CFG_LR_VPSTAT: + pdata->sdout_datacfg = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,sdout-datacfg DT value %d\n", val); + pdata->sdout_datacfg = CS35L32_DATA_CFG_LR; + } + + of_property_read_u32(np, "cirrus,battery-threshold", &val); + switch (val) { + case CS35L32_BATT_THRESH_3_1V: + case CS35L32_BATT_THRESH_3_2V: + case CS35L32_BATT_THRESH_3_3V: + case CS35L32_BATT_THRESH_3_4V: + pdata->batt_thresh = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,battery-threshold DT value %d\n", val); + pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V; + } + + of_property_read_u32(np, "cirrus,battery-recovery", &val); + switch (val) { + case CS35L32_BATT_RECOV_3_1V: + case CS35L32_BATT_RECOV_3_2V: + case CS35L32_BATT_RECOV_3_3V: + case CS35L32_BATT_RECOV_3_4V: + case CS35L32_BATT_RECOV_3_5V: + case CS35L32_BATT_RECOV_3_6V: + pdata->batt_recov = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,battery-recovery DT value %d\n", val); + pdata->batt_recov = CS35L32_BATT_RECOV_3_4V; + } + + return 0; +} + +static int cs35l32_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs35l32_private *cs35l32; + struct cs35l32_platform_data *pdata = + dev_get_platdata(&i2c_client->dev); + int ret, i; + unsigned int devid = 0; + unsigned int reg; + + + cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private), + GFP_KERNEL); + if (!cs35l32) { + dev_err(&i2c_client->dev, "could not allocate codec\n"); + return -ENOMEM; + } + + i2c_set_clientdata(i2c_client, cs35l32); + + cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap); + if (IS_ERR(cs35l32->regmap)) { + ret = PTR_ERR(cs35l32->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + if (pdata) { + cs35l32->pdata = *pdata; + } else { + pdata = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs35l32_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&i2c_client->dev, "could not allocate pdata\n"); + return -ENOMEM; + } + if (i2c_client->dev.of_node) { + ret = cs35l32_handle_of_data(i2c_client, + &cs35l32->pdata); + if (ret != 0) + return ret; + } + } + + for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++) + cs35l32->supplies[i].supply = cs35l32_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c_client->dev, + ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to enable supplies: %d\n", ret); + return ret; + } + + /* Reset the Device */ + cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev, + "reset-gpios"); + if (IS_ERR(cs35l32->reset_gpio)) { + ret = PTR_ERR(cs35l32->reset_gpio); + if (ret != -ENOENT && ret != -ENOSYS) + return ret; + + cs35l32->reset_gpio = NULL; + } else { + ret = gpiod_direction_output(cs35l32->reset_gpio, 0); + if (ret) + return ret; + gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); + } + + /* initialize codec */ + ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®); + devid = (reg & 0xFF) << 12; + + ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_CD, ®); + devid |= (reg & 0xFF) << 4; + + ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_E, ®); + devid |= (reg & 0xF0) >> 4; + + if (devid != CS35L32_CHIP_ID) { + ret = -ENODEV; + dev_err(&i2c_client->dev, + "CS35L32 Device ID (%X). Expected %X\n", + devid, CS35L32_CHIP_ID); + return ret; + } + + ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, ®); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + return ret; + } + + ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch, + ARRAY_SIZE(cs35l32_monitor_patch)); + if (ret < 0) { + dev_err(&i2c_client->dev, "Failed to apply errata patch\n"); + return ret; + } + + dev_info(&i2c_client->dev, + "Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF); + + /* Setup VBOOST Management */ + if (cs35l32->pdata.boost_mng) + regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR, + CS35L32_BOOST_MASK, + cs35l32->pdata.boost_mng); + + /* Setup ADSP Format Config */ + if (cs35l32->pdata.sdout_share) + regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL, + CS35L32_ADSP_SHARE_MASK, + cs35l32->pdata.sdout_share << 3); + + /* Setup ADSP Data Configuration */ + if (cs35l32->pdata.sdout_datacfg) + regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL, + CS35L32_ADSP_DATACFG_MASK, + cs35l32->pdata.sdout_datacfg << 4); + + /* Setup Low Battery Recovery */ + if (cs35l32->pdata.batt_recov) + regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD, + CS35L32_BATT_REC_MASK, + cs35l32->pdata.batt_recov << 1); + + /* Setup Low Battery Threshold */ + if (cs35l32->pdata.batt_thresh) + regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD, + CS35L32_BATT_THRESH_MASK, + cs35l32->pdata.batt_thresh << 4); + + /* Power down the AMP */ + regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP, + CS35L32_PDN_AMP); + + /* Clear MCLK Error Bit since we don't have the clock yet */ + ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, ®); + + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_dev_cs35l32, cs35l32_dai, + ARRAY_SIZE(cs35l32_dai)); + if (ret < 0) + goto err_disable; + + return 0; + +err_disable: + regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); +} + +static int cs35l32_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client); + + snd_soc_unregister_codec(&i2c_client->dev); + + /* Hold down reset */ + if (cs35l32->reset_gpio) + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + + regulator_bulk_free(ARRAY_SIZE(cs35l32->supplies), cs35l32->supplies); + + return 0; +} + +#ifdef CONFIG_PM_RUNTIME +static int cs35l32_runtime_suspend(struct device *dev) +{ + struct cs35l32_private *cs35l32 = dev_get_drvdata(dev); + + regcache_cache_only(cs35l32->regmap, true); + regcache_mark_dirty(cs35l32->regmap); + + /* Hold down reset */ + if (cs35l32->reset_gpio) + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + + /* remove power */ + regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + + return 0; +} + +static int cs35l32_runtime_resume(struct device *dev) +{ + struct cs35l32_private *cs35l32 = dev_get_drvdata(dev); + int ret; + + /* Enable power */ + ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", + ret); + return ret; + } + + if (cs35l32->reset_gpio) + gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); + + regcache_cache_only(cs35l32->regmap, false); + regcache_sync(cs35l32->regmap); + + return 0; +} +#endif + +static const struct dev_pm_ops cs35l32_runtime_pm = { + SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume, + NULL) +}; + +static const struct of_device_id cs35l32_of_match[] = { + { .compatible = "cirrus,cs35l32", }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l32_of_match); + + +static const struct i2c_device_id cs35l32_id[] = { + {"cs35l32", 0}, + {} +}; + +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, + }, + .id_table = cs35l32_id, + .probe = cs35l32_i2c_probe, + .remove = cs35l32_i2c_remove, +}; + +module_i2c_driver(cs35l32_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS35L32 driver"); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h new file mode 100644 index 000000000000..31ab804a22bc --- /dev/null +++ b/sound/soc/codecs/cs35l32.h @@ -0,0 +1,93 @@ +/* + * cs35l32.h -- CS35L32 ALSA SoC audio driver + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Brian Austin + * + * 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 __CS35L32_H__ +#define __CS35L32_H__ + +struct cs35l32_platform_data { + /* Low Battery Threshold */ + unsigned int batt_thresh; + /* Low Battery Recovery */ + unsigned int batt_recov; + /* LED Current Management*/ + unsigned int led_mng; + /* Audio Gain w/ LED */ + unsigned int audiogain_mng; + /* Boost Management */ + unsigned int boost_mng; + /* Data CFG for DUAL device */ + unsigned int sdout_datacfg; + /* SDOUT Sharing */ + unsigned int sdout_share; +}; + +#define CS35L32_CHIP_ID 0x00035A32 +#define CS35L32_DEVID_AB 0x01 /* Device ID A & B [RO] */ +#define CS35L32_DEVID_CD 0x02 /* Device ID C & D [RO] */ +#define CS35L32_DEVID_E 0x03 /* Device ID E [RO] */ +#define CS35L32_FAB_ID 0x04 /* Fab ID [RO] */ +#define CS35L32_REV_ID 0x05 /* Revision ID [RO] */ +#define CS35L32_PWRCTL1 0x06 /* Power Ctl 1 */ +#define CS35L32_PWRCTL2 0x07 /* Power Ctl 2 */ +#define CS35L32_CLK_CTL 0x08 /* Clock Ctl */ +#define CS35L32_BATT_THRESHOLD 0x09 /* Low Battery Threshold */ +#define CS35L32_VMON 0x0A /* Voltage Monitor [RO] */ +#define CS35L32_BST_CPCP_CTL 0x0B /* Conv Peak Curr Protection CTL */ +#define CS35L32_IMON_SCALING 0x0C /* IMON Scaling */ +#define CS35L32_AUDIO_LED_MNGR 0x0D /* Audio/LED Pwr Manager */ +#define CS35L32_ADSP_CTL 0x0F /* Serial Port Control */ +#define CS35L32_CLASSD_CTL 0x10 /* Class D Amp CTL */ +#define CS35L32_PROTECT_CTL 0x11 /* Protection Release CTL */ +#define CS35L32_INT_MASK_1 0x12 /* Interrupt Mask 1 */ +#define CS35L32_INT_MASK_2 0x13 /* Interrupt Mask 2 */ +#define CS35L32_INT_MASK_3 0x14 /* Interrupt Mask 3 */ +#define CS35L32_INT_STATUS_1 0x15 /* Interrupt Status 1 [RO] */ +#define CS35L32_INT_STATUS_2 0x16 /* Interrupt Status 2 [RO] */ +#define CS35L32_INT_STATUS_3 0x17 /* Interrupt Status 3 [RO] */ +#define CS35L32_LED_STATUS 0x18 /* LED Lighting Status [RO] */ +#define CS35L32_FLASH_MODE 0x19 /* LED Flash Mode Current */ +#define CS35L32_MOVIE_MODE 0x1A /* LED Movie Mode Current */ +#define CS35L32_FLASH_TIMER 0x1B /* LED Flash Timer */ +#define CS35L32_FLASH_INHIBIT 0x1C /* LED Flash Inhibit Current */ +#define CS35L32_MAX_REGISTER 0x1C + +#define CS35L32_MCLK_DIV2 0x01 +#define CS35L32_MCLK_RATIO 0x01 +#define CS35L32_MCLKDIS 0x80 +#define CS35L32_PDN_ALL 0x01 +#define CS35L32_PDN_AMP 0x80 +#define CS35L32_PDN_BOOST 0x04 +#define CS35L32_PDN_IMON 0x40 +#define CS35L32_PDN_VMON 0x80 +#define CS35L32_PDN_VPMON 0x20 +#define CS35L32_PDN_ADSP 0x08 + +#define CS35L32_MCLK_DIV2_MASK 0x40 +#define CS35L32_MCLK_RATIO_MASK 0x01 +#define CS35L32_MCLK_MASK 0x41 +#define CS35L32_ADSP_MASTER_MASK 0x40 +#define CS35L32_BOOST_MASK 0x03 +#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_BATT_REC_MASK 0x0E +#define CS35L32_BATT_THRESH_MASK 0x30 + +#define CS35L32_RATES (SNDRV_PCM_RATE_48000) +#define CS35L32_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + + +#endif -- GitLab From 9cf44690204db563ba065ed856546dc8a8b742a1 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Mon, 4 Aug 2014 15:11:17 -0500 Subject: [PATCH 0336/5088] ASoC: cs35l32: Add bindings for CS35L32 The patch adds device tree bindings file for the Cirrus Logic CS35L32 Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cs35l32.txt | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cs35l32.txt diff --git a/Documentation/devicetree/bindings/sound/cs35l32.txt b/Documentation/devicetree/bindings/sound/cs35l32.txt new file mode 100644 index 000000000000..1417d3f5cc22 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs35l32.txt @@ -0,0 +1,62 @@ +CS35L32 audio CODEC + +Required properties: + + - compatible : "cirrus,cs35l32" + + - reg : the I2C address of the device for I2C. Address is determined by the level + of the AD0 pin. Level 0 is 0x40 while Level 1 is 0x41. + + - VA-supply, VP-supply : power supplies for the device, + as covered in Documentation/devicetree/bindings/regulator/regulator.txt. + +Optional properties: + + - reset-gpios : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + + - cirrus,boost-manager : Boost voltage control. + 0 = Automatically managed. Boost-converter output voltage is the higher + of the two: Class G or adaptive LED voltage. + 1 = Automatically managed irrespective of audio, adapting for low-power + dissipation when LEDs are ON, and operating in Fixed-Boost Bypass Mode + if LEDs are OFF (VBST = VP). + 2 = (Default) Boost voltage fixed in Bypass Mode (VBST = VP). + 3 = Boost voltage fixed at 5 V. + + - cirrus,sdout-datacfg : Data configuration for dual CS35L32 applications only. + Determines the data packed in a two-CS35L32 configuration. + 0 = Left/right channels VMON[11:0], IMON[11:0], VPMON[7:0]. + 1 = Left/right channels VMON[11:0], IMON[11:0], STATUS. + 2 = (Default) left/right channels VMON[15:0], IMON [15:0]. + 3 = Left/right channels VPMON[7:0], STATUS. + + - cirrus,sdout-share : SDOUT sharing. Determines whether one or two CS35L32 + devices are on board sharing SDOUT. + 0 = (Default) One IC. + 1 = Two IC's. + + - cirrus,battery-recovery : Low battery nominal recovery threshold, rising VP. + 0 = 3.1V + 1 = 3.2V + 2 = 3.3V (Default) + 3 = 3.4V + + - cirrus,battery-threshold : Low battery nominal threshold, falling VP. + 0 = 3.1V + 1 = 3.2V + 2 = 3.3V + 3 = 3.4V (Default) + 4 = 3.5V + 5 = 3.6V + +Example: + +codec: codec@40 { + compatible = "cirrus,cs35l32"; + reg = <0x40>; + reset-gpios = <&gpio 10 0>; + cirrus,boost-manager = <0x03>; + cirrus,sdout-datacfg = <0x02>; + VA-supply = <®_audio>; +}; -- GitLab From 38f57532ede565a3c71da7b7727369f374c51acb Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 7 Aug 2014 09:34:38 -0500 Subject: [PATCH 0337/5088] ASoC: cs35l32: fix compile warning for i2c_probe Forgot to add a return for err_disable goto statement. Causes compile warning of control reaching end of non-void Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 90565d59def7..9c6b2723d343 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -549,6 +549,7 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, err_disable: regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), cs35l32->supplies); + return ret; } static int cs35l32_i2c_remove(struct i2c_client *i2c_client) -- GitLab From 708b4351f08c08ea93f773fb9197bdd3f3b08273 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Wed, 30 Jul 2014 19:27:38 +0800 Subject: [PATCH 0338/5088] ASoC: fsl: Add Freescale Generic ASoC Sound Card with ASRC support The Freescale Generic ASoC Sound Card is a general ASoC DAI Link driver that can be used, ideally, for all Freescale CPU DAI drivers and external CODECs. The idea of this generic sound card is a bit like ASoC Simple Card. However, for Freescale SoCs (especially those released in recent years), most of them have ASRC (Documentation/devicetree/bindings/sound/fsl,asrc.txt) inside. And this is a specific feature that might be painstakingly controlled and merged into the Simple Card driver. So having this driver will allow all Freescale SoC users to benefit from the simplification to support a new card and the capability of wide sample rates support through ASRC. The driver is initially designed for sound card using I2S or PCM DAI formats. However, it's also possible to merge those non-I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, into this card as long as the merge will not break the original function and as long as there is something redundant that can be abstracted along with I2S type sound cards. As an initial version, it only supports three cards that I can test: imx-audio-cs42888, a new card that links ESAI with CS42888 CODEC imx-audio-sgtl5000, just like the old imx-sgtl5000.c driver imx-audio-wm8962, just like the old imx-wm8962.c driver The driver is also compatible with the old Device Tree bindings of WM8962 and SGTL5000. So we may consider to remove those two drivers after this driver is totally enabled. (It needs to be added into defconfig) Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../bindings/sound/fsl-asoc-card.txt | 82 +++ sound/soc/fsl/Kconfig | 16 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl-asoc-card.c | 573 ++++++++++++++++++ 4 files changed, 673 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl-asoc-card.txt create mode 100644 sound/soc/fsl/fsl-asoc-card.c diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt new file mode 100644 index 000000000000..a96774c194c8 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt @@ -0,0 +1,82 @@ +Freescale Generic ASoC Sound Card with ASRC support + +The Freescale Generic ASoC Sound Card can be used, ideally, for all Freescale +SoCs connecting with external CODECs. + +The idea of this generic sound card is a bit like ASoC Simple Card. However, +for Freescale SoCs (especially those released in recent years), most of them +have ASRC (Documentation/devicetree/bindings/sound/fsl,asrc.txt) inside. And +this is a specific feature that might be painstakingly controlled and merged +into the Simple Card. + +So having this generic sound card allows all Freescale SoC users to benefit +from the simplification of a new card support and the capability of the wide +sample rates support through ASRC. + +Note: The card is initially designed for those sound cards who use I2S and + PCM DAI formats. However, it'll be also possible to support those non + I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as long + as the driver has been properly upgraded. + + +The compatible list for this generic sound card currently: + "fsl,imx-audio-cs42888" + + "fsl,imx-audio-wm8962" + (compatible with Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt) + + "fsl,imx-audio-sgtl5000" + (compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt) + +Required properties: + + - compatible : Contains one of entries in the compatible list. + + - model : The user-visible name of this sound complex + + - audio-cpu : The phandle of an CPU DAI controller + + - audio-codec : The phandle of an audio codec + + - 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. There're a few pre-designed board connectors: + * Line Out Jack + * Line In Jack + * Headphone Jack + * Mic Jack + * Ext Spk + * AMIC (stands for Analog Microphone Jack) + * DMIC (stands for Digital Microphone Jack) + + Note: The "Mic Jack" and "AMIC" are redundant while + coexsiting in order to support the old bindings + of wm8962 and sgtl5000. + +Optional properties: + + - audio-asrc : The phandle of ASRC. It can be absent if there's no + need to add ASRC support via DPCM. + +Example: +sound-cs42888 { + compatible = "fsl,imx-audio-cs42888"; + model = "cs42888-audio"; + audio-cpu = <&esai>; + audio-asrc = <&asrc>; + audio-codec = <&cs42888>; + audio-routing = + "Line Out Jack", "AOUT1L", + "Line Out Jack", "AOUT1R", + "Line Out Jack", "AOUT2L", + "Line Out Jack", "AOUT2R", + "Line Out Jack", "AOUT3L", + "Line Out Jack", "AOUT3R", + "Line Out Jack", "AOUT4L", + "Line Out Jack", "AOUT4R", + "AIN1L", "Line In Jack", + "AIN1R", "Line In Jack", + "AIN2L", "Line In Jack", + "AIN2R", "Line In Jack"; +}; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index f54a8fc99291..2b99a9e86899 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -59,6 +59,22 @@ config SND_SOC_FSL_ESAI config SND_SOC_FSL_UTILS tristate +config SND_SOC_FSL_ASOC_CARD + tristate "Generic ASoC Sound Card with ASRC support" + depends on OF && I2C + select SND_SOC_IMX_PCM_DMA + select SND_SOC_FSL_ESAI + select SND_SOC_FSL_SAI + select SND_SOC_FSL_SSI + select SND_SOC_CS42XX8_I2C + select SND_SOC_SGTL5000 + select SND_SOC_WM8962 + help + ALSA SoC Audio support with ASRC feature for Freescale SoCs that have + ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888 + and SGTL5000. + Say Y if you want to add support for Freescale Generic ASoC Sound Card. + config SND_SOC_IMX_PCM_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 9ff59267eac9..8f6d84efa973 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -11,6 +11,7 @@ snd-soc-p1022-rdk-objs := p1022_rdk.o obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o # Freescale SSI/DMA/SAI/SPDIF Support +snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o snd-soc-fsl-sai-objs := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o @@ -19,6 +20,7 @@ snd-soc-fsl-spdif-objs := fsl_spdif.o snd-soc-fsl-esai-objs := fsl_esai.o snd-soc-fsl-utils-objs := fsl_utils.o snd-soc-fsl-dma-objs := fsl_dma.o +obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c new file mode 100644 index 000000000000..cf3f1f47f1e8 --- /dev/null +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -0,0 +1,573 @@ +/* + * Freescale Generic ASoC Sound Card driver with ASRC + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen + * + * 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 + +#include "fsl_esai.h" +#include "fsl_sai.h" +#include "imx-audmux.h" + +#include "../codecs/sgtl5000.h" +#include "../codecs/wm8962.h" + +#define RX 0 +#define TX 1 + +/* Default DAI format without Master and Slave flag */ +#define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF) + +/** + * CODEC private data + * + * @mclk_freq: Clock rate of MCLK + * @mclk_id: MCLK (or main clock) id for set_sysclk() + * @fll_id: FLL (or secordary clock) id for set_sysclk() + * @pll_id: PLL id for set_pll() + */ +struct codec_priv { + unsigned long mclk_freq; + u32 mclk_id; + u32 fll_id; + u32 pll_id; +}; + +/** + * CPU private data + * + * @sysclk_freq[2]: SYSCLK rates for set_sysclk() + * @sysclk_dir[2]: SYSCLK directions for set_sysclk() + * @sysclk_id[2]: SYSCLK ids for set_sysclk() + * + * Note: [1] for tx and [0] for rx + */ +struct cpu_priv { + unsigned long sysclk_freq[2]; + u32 sysclk_dir[2]; + u32 sysclk_id[2]; +}; + +/** + * Freescale Generic ASOC card private data + * + * @dai_link[3]: DAI link structure including normal one and DPCM link + * @pdev: platform device pointer + * @codec_priv: CODEC private data + * @cpu_priv: CPU private data + * @card: ASoC card structure + * @sample_rate: Current sample rate + * @sample_format: Current sample format + * @asrc_rate: ASRC sample rate used by Back-Ends + * @asrc_format: ASRC sample format used by Back-Ends + * @dai_fmt: DAI format between CPU and CODEC + * @name: Card name + */ + +struct fsl_asoc_card_priv { + struct snd_soc_dai_link dai_link[3]; + struct platform_device *pdev; + struct codec_priv codec_priv; + struct cpu_priv cpu_priv; + struct snd_soc_card card; + u32 sample_rate; + u32 sample_format; + u32 asrc_rate; + u32 asrc_format; + u32 dai_fmt; + char name[32]; +}; + +/** + * This dapm route map exsits for DPCM link only. + * The other routes shall go through Device Tree. + */ +static const struct snd_soc_dapm_route audio_map[] = { + {"CPU-Playback", NULL, "ASRC-Playback"}, + {"Playback", NULL, "CPU-Playback"}, + {"ASRC-Capture", NULL, "CPU-Capture"}, + {"CPU-Capture", NULL, "Capture"}, +}; + +/* Add all possible widgets into here without being redundant */ +static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = { + SND_SOC_DAPM_LINE("Line Out Jack", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("AMIC", NULL), + SND_SOC_DAPM_MIC("DMIC", NULL), +}; + +static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct cpu_priv *cpu_priv = &priv->cpu_priv; + struct device *dev = rtd->card->dev; + int ret; + + priv->sample_rate = params_rate(params); + priv->sample_format = params_format(params); + + if (priv->card.set_bias_level) + return 0; + + /* Specific configurations of DAIs starts from here */ + ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, cpu_priv->sysclk_id[tx], + cpu_priv->sysclk_freq[tx], + cpu_priv->sysclk_dir[tx]); + if (ret) { + dev_err(dev, "failed to set sysclk for cpu dai\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops fsl_asoc_card_ops = { + .hw_params = fsl_asoc_card_hw_params, +}; + +static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct snd_interval *rate; + struct snd_mask *mask; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + rate->max = rate->min = priv->asrc_rate; + + mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + snd_mask_none(mask); + snd_mask_set(mask, priv->asrc_format); + + return 0; +} + +static struct snd_soc_dai_link fsl_asoc_card_dai[] = { + /* Default ASoC DAI Link*/ + { + .name = "HiFi", + .stream_name = "HiFi", + .ops = &fsl_asoc_card_ops, + }, + /* DPCM Link between Front-End and Back-End (Optional) */ + { + .name = "HiFi-ASRC-FE", + .stream_name = "HiFi-ASRC-FE", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .dpcm_playback = 1, + .dpcm_capture = 1, + .dynamic = 1, + }, + { + .name = "HiFi-ASRC-BE", + .stream_name = "HiFi-ASRC-BE", + .platform_name = "snd-soc-dummy", + .be_hw_params_fixup = be_hw_params_fixup, + .ops = &fsl_asoc_card_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, +}; + +static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct codec_priv *codec_priv = &priv->codec_priv; + struct device *dev = card->dev; + unsigned int pll_out; + int ret; + + if (dapm->dev != codec_dai->dev) + return 0; + + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level != SND_SOC_BIAS_STANDBY) + break; + + if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE) + pll_out = priv->sample_rate * 384; + else + pll_out = priv->sample_rate * 256; + + ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, + codec_priv->mclk_id, + codec_priv->mclk_freq, pll_out); + if (ret) { + dev_err(dev, "failed to start FLL: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->fll_id, + pll_out, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "failed to set SYSCLK: %d\n", ret); + return ret; + } + break; + + case SND_SOC_BIAS_STANDBY: + if (dapm->bias_level != SND_SOC_BIAS_PREPARE) + break; + + ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, + codec_priv->mclk_freq, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "failed to switch away from FLL: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, 0, 0, 0); + if (ret) { + dev_err(dev, "failed to stop FLL: %d\n", ret); + return ret; + } + break; + + default: + break; + } + + return 0; +} + +static int fsl_asoc_card_audmux_init(struct device_node *np, + struct fsl_asoc_card_priv *priv) +{ + struct device *dev = &priv->pdev->dev; + u32 int_ptcr = 0, ext_ptcr = 0; + int int_port, ext_port; + int ret; + + ret = of_property_read_u32(np, "mux-int-port", &int_port); + if (ret) { + dev_err(dev, "mux-int-port missing or invalid\n"); + return ret; + } + ret = of_property_read_u32(np, "mux-ext-port", &ext_port); + if (ret) { + dev_err(dev, "mux-ext-port missing or invalid\n"); + return ret; + } + + /* + * The port numbering in the hardware manual starts at 1, while + * the AUDMUX API expects it starts at 0. + */ + int_port--; + ext_port--; + + /* + * Use asynchronous mode (6 wires) for all cases. + * If only 4 wires are needed, just set SSI into + * synchronous mode and enable 4 PADs in IOMUX. + */ + switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + int_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(int_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR; + break; + case SND_SOC_DAIFMT_CBS_CFM: + int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR; + ext_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(int_port) | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + break; + case SND_SOC_DAIFMT_CBS_CFS: + ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(int_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(int_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + break; + default: + return -EINVAL; + } + + /* Asynchronous mode can not be set along with RCLKDIR */ + ret = imx_audmux_v2_configure_port(int_port, 0, + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); + if (ret) { + dev_err(dev, "audmux internal port setup failed\n"); + return ret; + } + + ret = imx_audmux_v2_configure_port(int_port, int_ptcr, + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); + if (ret) { + dev_err(dev, "audmux internal port setup failed\n"); + return ret; + } + + ret = imx_audmux_v2_configure_port(ext_port, 0, + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); + if (ret) { + dev_err(dev, "audmux external port setup failed\n"); + return ret; + } + + ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr, + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); + if (ret) { + dev_err(dev, "audmux external port setup failed\n"); + return ret; + } + + return 0; +} + +static int fsl_asoc_card_late_probe(struct snd_soc_card *card) +{ + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct codec_priv *codec_priv = &priv->codec_priv; + struct device *dev = card->dev; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, + codec_priv->mclk_freq, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "failed to set sysclk in %s\n", __func__); + return ret; + } + + return 0; +} + +static int fsl_asoc_card_probe(struct platform_device *pdev) +{ + struct device_node *cpu_np, *codec_np, *asrc_np; + struct device_node *np = pdev->dev.of_node; + struct platform_device *asrc_pdev = NULL; + struct platform_device *cpu_pdev; + struct fsl_asoc_card_priv *priv; + struct i2c_client *codec_dev; + struct clk *codec_clk; + u32 width; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + cpu_np = of_parse_phandle(np, "audio-cpu", 0); + /* Give a chance to old DT binding */ + if (!cpu_np) + cpu_np = of_parse_phandle(np, "ssi-controller", 0); + codec_np = of_parse_phandle(np, "audio-codec", 0); + if (!cpu_np || !codec_np) { + dev_err(&pdev->dev, "phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + cpu_pdev = of_find_device_by_node(cpu_np); + if (!cpu_pdev) { + dev_err(&pdev->dev, "failed to find CPU DAI device\n"); + ret = -EINVAL; + goto fail; + } + + codec_dev = of_find_i2c_device_by_node(codec_np); + if (!codec_dev) { + dev_err(&pdev->dev, "failed to find codec platform device\n"); + ret = -EINVAL; + goto fail; + } + + asrc_np = of_parse_phandle(np, "audio-asrc", 0); + if (asrc_np) + asrc_pdev = of_find_device_by_node(asrc_np); + + /* Get the MCLK rate only, and leave it controlled by CODEC drivers */ + codec_clk = clk_get(&codec_dev->dev, NULL); + if (!IS_ERR(codec_clk)) { + priv->codec_priv.mclk_freq = clk_get_rate(codec_clk); + clk_put(codec_clk); + } + + /* Default sample rate and format, will be updated in hw_params() */ + priv->sample_rate = 44100; + priv->sample_format = SNDRV_PCM_FORMAT_S16_LE; + + /* Assign a default DAI format, and allow each card to overwrite it */ + priv->dai_fmt = DAI_FMT_BASE; + + /* Diversify the card configurations */ + if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) { + priv->card.set_bias_level = NULL; + priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq; + priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq; + priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; + priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; + priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { + priv->codec_priv.mclk_id = SGTL5000_SYSCLK; + priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) { + priv->card.set_bias_level = fsl_asoc_card_set_bias_level; + priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK; + priv->codec_priv.fll_id = WM8962_SYSCLK_FLL; + priv->codec_priv.pll_id = WM8962_FLL; + priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + } else { + dev_err(&pdev->dev, "unknown Device Tree compatible\n"); + return -EINVAL; + } + + /* Common settings for corresponding Freescale CPU DAI driver */ + if (strstr(cpu_np->name, "ssi")) { + /* Only SSI needs to configure AUDMUX */ + ret = fsl_asoc_card_audmux_init(np, priv); + if (ret) { + dev_err(&pdev->dev, "failed to init audmux\n"); + goto fail; + } + } else if (strstr(cpu_np->name, "esai")) { + priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; + priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL; + } else if (strstr(cpu_np->name, "sai")) { + priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; + priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; + } + + sprintf(priv->name, "%s-audio", codec_dev->name); + + /* Initialize sound card */ + priv->pdev = pdev; + priv->card.dev = &pdev->dev; + priv->card.name = priv->name; + priv->card.dai_link = priv->dai_link; + priv->card.dapm_routes = audio_map; + priv->card.late_probe = fsl_asoc_card_late_probe; + priv->card.num_dapm_routes = ARRAY_SIZE(audio_map); + priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets; + priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets); + + memcpy(priv->dai_link, fsl_asoc_card_dai, + sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link)); + + /* Normal DAI Link */ + priv->dai_link[0].cpu_of_node = cpu_np; + priv->dai_link[0].codec_of_node = codec_np; + priv->dai_link[0].codec_dai_name = codec_dev->name; + priv->dai_link[0].platform_of_node = cpu_np; + priv->dai_link[0].dai_fmt = priv->dai_fmt; + priv->card.num_links = 1; + + if (asrc_pdev) { + /* DPCM DAI Links only if ASRC exsits */ + priv->dai_link[1].cpu_of_node = asrc_np; + priv->dai_link[1].platform_of_node = asrc_np; + priv->dai_link[2].codec_dai_name = codec_dev->name; + priv->dai_link[2].codec_of_node = codec_np; + priv->dai_link[2].cpu_of_node = cpu_np; + priv->dai_link[2].dai_fmt = priv->dai_fmt; + priv->card.num_links = 3; + + ret = of_property_read_u32(asrc_np, "fsl,asrc-rate", + &priv->asrc_rate); + if (ret) { + dev_err(&pdev->dev, "failed to get output rate\n"); + ret = -EINVAL; + goto fail; + } + + ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width); + if (ret) { + dev_err(&pdev->dev, "failed to get output rate\n"); + ret = -EINVAL; + goto fail; + } + + if (width == 24) + priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE; + else + priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE; + } + + /* Finish card registering */ + platform_set_drvdata(pdev, priv); + snd_soc_card_set_drvdata(&priv->card, priv); + + ret = devm_snd_soc_register_card(&pdev->dev, &priv->card); + if (ret) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + +fail: + of_node_put(codec_np); + of_node_put(asrc_np); + of_node_put(cpu_np); + + return ret; +} + +static const struct of_device_id fsl_asoc_card_dt_ids[] = { + { .compatible = "fsl,imx-audio-cs42888", }, + { .compatible = "fsl,imx-audio-sgtl5000", }, + { .compatible = "fsl,imx-audio-wm8962", }, + {} +}; + +static struct platform_driver fsl_asoc_card_driver = { + .probe = fsl_asoc_card_probe, + .driver = { + .name = "fsl-asoc-card", + .pm = &snd_soc_pm_ops, + .of_match_table = fsl_asoc_card_dt_ids, + }, +}; +module_platform_driver(fsl_asoc_card_driver); + +MODULE_DESCRIPTION("Freescale Generic ASoC Sound Card driver with ASRC"); +MODULE_AUTHOR("Nicolin Chen "); +MODULE_ALIAS("platform:fsl-asoc-card"); +MODULE_LICENSE("GPL"); -- GitLab From de0d712a6dd1eed097dc6aa4f97ee461949414fe Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 8 Aug 2014 14:47:21 +0800 Subject: [PATCH 0339/5088] ASoC: fsl_esai: refine esai for TDM support Original driver didn't store the number of slots, just fix the slot number to 2, use this default number to calculate bclk and pins for TX/RX. In this patch, add one parameter for slots, and update the calculation of bclk and pins of TX/RX. Then driver will be compatible with slots > 2 in TDM mode. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 14 +++++++++++--- sound/soc/fsl/fsl_esai.h | 8 ++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 72d154e7dd03..f252370073e5 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -38,6 +38,7 @@ * @fsysclk: system clock source to derive HCK, SCK and FS * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot + * @slots: number of slots * @hck_rate: clock rate of desired HCKx clock * @sck_rate: clock rate of desired SCKx clock * @hck_dir: the direction of HCKx pads @@ -56,6 +57,7 @@ struct fsl_esai { struct clk *fsysclk; u32 fifo_depth; u32 slot_width; + u32 slots; u32 hck_rate[2]; u32 sck_rate[2]; bool hck_dir[2]; @@ -363,6 +365,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); esai_priv->slot_width = slot_width; + esai_priv->slots = slots; return 0; } @@ -510,10 +513,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 width = snd_pcm_format_width(params_format(params)); u32 channels = params_channels(params); + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); u32 bclk, mask, val; int ret; - bclk = params_rate(params) * esai_priv->slot_width * 2; + bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots; ret = fsl_esai_set_bclk(dai, tx, bclk); if (ret) @@ -530,7 +534,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK | (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK); val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) | - (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels)); + (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins)); regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); @@ -565,6 +569,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u8 i, channels = substream->runtime->channels; + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -579,7 +584,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, - tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels)); + tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: @@ -783,6 +788,9 @@ static int fsl_esai_probe(struct platform_device *pdev) /* Set a default slot size */ esai_priv->slot_width = 32; + /* Set a default slot number */ + esai_priv->slots = 2; + /* Set a default master/slave state */ esai_priv->slave_mode = true; diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h index 75e14033e8d8..91a550f4a10d 100644 --- a/sound/soc/fsl/fsl_esai.h +++ b/sound/soc/fsl/fsl_esai.h @@ -130,8 +130,8 @@ #define ESAI_xFCR_RE_WIDTH 4 #define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) #define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) -#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK) -#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK) +#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - x)) & ESAI_xFCR_TE_MASK) +#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - x)) & ESAI_xFCR_RE_MASK) #define ESAI_xFCR_xFR_SHIFT 1 #define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT) #define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT) @@ -272,8 +272,8 @@ #define ESAI_xCR_RE_WIDTH 4 #define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) #define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) -#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK) -#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK) +#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - x)) & ESAI_xCR_TE_MASK) +#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - x)) & ESAI_xCR_RE_MASK) /* * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8 -- GitLab From 376d1a92ca587d3974d4791cdb99baa8b8e7f0dd Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 5 Aug 2014 17:20:21 +0800 Subject: [PATCH 0340/5088] ASoC: fsl_sai: Initialize with software reset This patch adds software reset code in dai_probe() so as to make a true init by clearing SAI's internal logic, including the bit clock generation, status flags, and FIFO pointers. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 9 +++++++-- sound/soc/fsl/fsl_sai.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index faa049797897..7b1eecbc4f60 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -437,8 +437,13 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0); + /* Software Reset for both Tx and Rx */ + regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); + /* Clear SR bit to finish the reset */ + regmap_write(sai->regmap, FSL_SAI_TCSR, 0); + regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_TX * 2); regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 0e6c9f595d75..8e1feab7c2a0 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -48,6 +48,7 @@ /* SAI Transmit/Recieve Control Register */ #define FSL_SAI_CSR_TERE BIT(31) #define FSL_SAI_CSR_FR BIT(25) +#define FSL_SAI_CSR_SR BIT(24) #define FSL_SAI_CSR_xF_SHIFT 16 #define FSL_SAI_CSR_xF_W_SHIFT 18 #define FSL_SAI_CSR_xF_MASK (0x1f << FSL_SAI_CSR_xF_SHIFT) -- GitLab From af96ff5b7448dc776dc24a5c4313c6ec1ee94e53 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Mon, 4 Aug 2014 15:07:25 +0800 Subject: [PATCH 0341/5088] ASoC: fsl_sai: Set SYNC bit of TCR2 to Asynchronous Mode There is one design rule according to SAI's reference manual: If the transmitter bit clock and frame sync are to be used by both transmitter and receiver, the transmitter must be configured for asynchronous operation and the receiver for synchronous operation. And SYNC of TCR2 is a 2-width control bit: 00 Asynchronous mode. 01 Synchronous with receiver. 10 Synchronous with another SAI transmitter. 11 Synchronous with another SAI receiver. So the driver should have set SYNC bit of TCR2 to 0x0, and meanwhile set SYNC bit of RCR2 to 0x1 (Synchronous with transmitter). Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 7b1eecbc4f60..3d865ad466ad 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -333,8 +333,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, * The transmitter bit clock and frame sync are to be * used by both the transmitter and receiver. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, - ~FSL_SAI_CR2_SYNC); + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, FSL_SAI_CR2_SYNC); -- GitLab From 08fdf65e37d560581233e06a659f73deeb3766f9 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 5 Aug 2014 15:32:05 +0800 Subject: [PATCH 0342/5088] ASoC: fsl_sai: Add asynchronous mode support SAI supports these operation modes: 1) asynchronous mode Both Tx and Rx are set to be asynchronous. 2) synchronous mode (Rx sync with Tx) Tx is set to be asynchronous, Rx is set to be synchronous. 3) synchronous mode (Tx sync with Rx) Rx is set to be asynchronous, Tx is set to be synchronous. 4) synchronous mode (Tx/Rx sync with another SAI's Tx) 5) synchronous mode (Tx/Rx sync with another SAI's Rx) * 4) and 5) are beyond this patch because they are related with another SAI. As the initial version of this SAI driver, it supported 2) as default while the others were totally missing. So this patch just adds supports for 1) and 3). Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl-sai.txt | 16 ++++++++++ sound/soc/fsl/fsl_sai.c | 30 ++++++++++++++++--- sound/soc/fsl/fsl_sai.h | 4 +++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 0f4e23828190..77864f4dd352 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -24,6 +24,22 @@ Required properties: - big-endian-data: If this property is absent, the little endian mode will be in use as default, or the big endian mode will be in use for all the fifo data. +- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating + that SAI will work in the synchronous mode (sync Tx with Rx) which means + both the transimitter and receiver will send and receive data by following + receiver's bit clocks and frame sync clocks. +- fsl,sai-asynchronous: This is a boolean property. If present, indicating + that SAI will work in the asynchronous mode, which means both transimitter + and receiver will send and receive data by following their own bit clocks + and frame sync clocks separately. + +Note: +- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the + default synchronous mode (sync Rx with Tx) will be used, which means both + transimitter and receiver will send and receive data by following clocks + of transimitter. +- fsl,sai-asynchronous will be ignored if fsl,sai-synchronous-rx property is + already present. Example: sai2: sai@40031000 { diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 3d865ad466ad..ef7c758627b1 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -330,12 +330,14 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, u32 xcsr, count = 100; /* - * The transmitter bit clock and frame sync are to be - * used by both the transmitter and receiver. + * Asynchronous mode: Clear SYNC for both Tx and Rx. + * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. + * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0); + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, + sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, - FSL_SAI_CR2_SYNC); + sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); /* * It is recommended that the transmitter is the last enabled @@ -625,6 +627,26 @@ static int fsl_sai_probe(struct platform_device *pdev) return ret; } + /* Sync Tx with Rx as default by following old DT binding */ + sai->synchronous[RX] = true; + sai->synchronous[TX] = false; + fsl_sai_dai.symmetric_rates = 1; + fsl_sai_dai.symmetric_channels = 1; + fsl_sai_dai.symmetric_samplebits = 1; + + if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) { + /* Sync Rx with Tx */ + sai->synchronous[RX] = false; + sai->synchronous[TX] = true; + } else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) { + /* Discard all settings for asynchronous mode */ + sai->synchronous[RX] = false; + sai->synchronous[TX] = false; + fsl_sai_dai.symmetric_rates = 0; + fsl_sai_dai.symmetric_channels = 0; + fsl_sai_dai.symmetric_samplebits = 0; + } + sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 8e1feab7c2a0..b3d8864cd5f2 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -136,9 +136,13 @@ struct fsl_sai { bool big_endian_data; bool is_dsp_mode; bool sai_on_imx; + bool synchronous[2]; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; }; +#define TX 1 +#define RX 0 + #endif /* __FSL_SAI_H */ -- GitLab From ce7344a4ebabe90e064d3e087727f45624cdc942 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Fri, 8 Aug 2014 18:41:19 +0800 Subject: [PATCH 0343/5088] ASoC: fsl_sai: Make Synchronous and Asynchronous modes exclusive The previous patch (ASoC: fsl_sai: Add asynchronous mode support) added new Device Tree bindings for Asynchronous and Synchronous modes support. However, these two shall not be present at the same time. So this patch just simply makes them exclusive so as to avoid incorrect Device Tree binding usage. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl-sai.txt | 3 +-- sound/soc/fsl/fsl_sai.c | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 77864f4dd352..dc9f9c356268 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -38,8 +38,7 @@ Note: default synchronous mode (sync Rx with Tx) will be used, which means both transimitter and receiver will send and receive data by following clocks of transimitter. -- fsl,sai-asynchronous will be ignored if fsl,sai-synchronous-rx property is - already present. +- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive. Example: sai2: sai@40031000 { diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index ef7c758627b1..4c9e71c2f52a 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -634,6 +634,13 @@ static int fsl_sai_probe(struct platform_device *pdev) fsl_sai_dai.symmetric_channels = 1; fsl_sai_dai.symmetric_samplebits = 1; + if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) && + of_find_property(np, "fsl,sai-asynchronous", NULL)) { + /* error out if both synchronous and asynchronous are present */ + dev_err(&pdev->dev, "invalid binding for synchronous mode\n"); + return -EINVAL; + } + if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) { /* Sync Rx with Tx */ sai->synchronous[RX] = false; -- GitLab From ea5edfe2f1ce5b2254a5ec4c1bb224fac48c3153 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 4 Aug 2014 15:04:19 +0530 Subject: [PATCH 0344/5088] ASoC: Intel: Fix to use byte control interface Using a byte control interface instead of generic_params ioctl. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 6c6a42c08e24..cc3a088df7dd 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -63,9 +63,7 @@ enum sst_controls { SST_SND_BUFFER_POINTER = 0x05, SST_SND_STREAM_INIT = 0x06, SST_SND_START = 0x07, - SST_SET_BYTE_STREAM = 0x100A, - SST_GET_BYTE_STREAM = 0x100B, - SST_MAX_CONTROLS = SST_GET_BYTE_STREAM, + SST_MAX_CONTROLS = 0x07, }; enum sst_stream_ops { @@ -129,7 +127,7 @@ struct compress_sst_ops { struct sst_ops { int (*open) (struct snd_sst_params *str_param); int (*device_control) (int cmd, void *arg); - int (*set_generic_params)(enum sst_controls cmd, void *arg); + int (*send_byte_stream)(struct snd_sst_bytes_v2 *bytes); int (*close) (unsigned int str_id); }; -- GitLab From 5981c2d6db2ef16d96ee4d1c4d3ddff4ad9d8ebc Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 4 Aug 2014 15:04:20 +0530 Subject: [PATCH 0345/5088] ASoC: Intel: mfld-pcm: Use function instead of ioctl Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-pcm.c | 21 +++++++++------------ sound/soc/intel/sst-mfld-platform.h | 19 ++++++------------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 706212a6a68c..42766a51c17e 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -314,8 +314,7 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) stream->stream_info.arg = substream; stream->stream_info.buffer_ptr = 0; stream->stream_info.sfreq = substream->runtime->rate; - ret_val = stream->ops->device_control( - SST_SND_STREAM_INIT, &stream->stream_info); + ret_val = stream->ops->stream_init(&stream->stream_info); if (ret_val) pr_err("control_set ret error %d\n", ret_val); return ret_val; @@ -403,8 +402,7 @@ static int sst_media_prepare(struct snd_pcm_substream *substream, stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; if (stream->stream_info.str_id) { - ret_val = stream->ops->device_control( - SST_SND_DROP, &str_id); + ret_val = stream->ops->stream_drop(str_id); return ret_val; } @@ -461,7 +459,7 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, { int ret_val = 0, str_id; struct sst_runtime_stream *stream; - int str_cmd, status; + int status; pr_debug("sst_platform_pcm_trigger called\n"); stream = substream->runtime->private_data; @@ -469,29 +467,29 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: pr_debug("sst: Trigger Start\n"); - str_cmd = SST_SND_START; status = SST_PLATFORM_RUNNING; stream->stream_info.arg = substream; + ret_val = stream->ops->stream_start(str_id); break; case SNDRV_PCM_TRIGGER_STOP: pr_debug("sst: in stop\n"); - str_cmd = SST_SND_DROP; status = SST_PLATFORM_DROPPED; + ret_val = stream->ops->stream_drop(str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: pr_debug("sst: in pause\n"); - str_cmd = SST_SND_PAUSE; status = SST_PLATFORM_PAUSED; + ret_val = stream->ops->stream_pause(str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: pr_debug("sst: in pause release\n"); - str_cmd = SST_SND_RESUME; status = SST_PLATFORM_RUNNING; + ret_val = stream->ops->stream_pause_release(str_id); break; default: return -EINVAL; } - ret_val = stream->ops->device_control(str_cmd, &str_id); + if (!ret_val) sst_set_stream_status(stream, status); @@ -511,8 +509,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer if (status == SST_PLATFORM_INIT) return 0; str_info = &stream->stream_info; - ret_val = stream->ops->device_control( - SST_SND_BUFFER_POINTER, str_info); + ret_val = stream->ops->stream_read_tstamp(str_info); if (ret_val) { pr_err("sst: error code = %d\n", ret_val); return ret_val; diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index cc3a088df7dd..2d6e65bbbc49 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -54,18 +54,6 @@ enum sst_drv_status { SST_PLATFORM_DROPPED, }; -enum sst_controls { - SST_SND_ALLOC = 0x00, - SST_SND_PAUSE = 0x01, - SST_SND_RESUME = 0x02, - SST_SND_DROP = 0x03, - SST_SND_FREE = 0x04, - SST_SND_BUFFER_POINTER = 0x05, - SST_SND_STREAM_INIT = 0x06, - SST_SND_START = 0x07, - SST_MAX_CONTROLS = 0x07, -}; - enum sst_stream_ops { STREAM_OPS_PLAYBACK = 0, STREAM_OPS_CAPTURE, @@ -126,7 +114,12 @@ struct compress_sst_ops { struct sst_ops { int (*open) (struct snd_sst_params *str_param); - int (*device_control) (int cmd, void *arg); + int (*stream_init) (struct pcm_stream_info *str_info); + int (*stream_start) (int str_id); + int (*stream_drop) (int str_id); + int (*stream_pause) (int str_id); + int (*stream_pause_release) (int str_id); + int (*stream_read_tstamp) (struct pcm_stream_info *str_info); int (*send_byte_stream)(struct snd_sst_bytes_v2 *bytes); int (*close) (unsigned int str_id); }; -- GitLab From b12b087c8715286b8759016f1d5c36cac0bb37f6 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 4 Aug 2014 15:04:21 +0530 Subject: [PATCH 0346/5088] ASoC: Intel: mfld-pcm: Change sst_ops prototypes to take dev parameter sst_ops need to use the sst driver context. So pass sst device as argument, which can be used to retrieve sst context. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-pcm.c | 19 +++++++++---------- sound/soc/intel/sst-mfld-platform.h | 18 +++++++++--------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 42766a51c17e..a89ff7e18e1a 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -277,7 +277,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, stream->stream_info.str_id = str_params.stream_id; - ret_val = stream->ops->open(&str_params); + ret_val = stream->ops->open(sst->dev, &str_params); if (ret_val <= 0) return ret_val; @@ -314,13 +314,12 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) stream->stream_info.arg = substream; stream->stream_info.buffer_ptr = 0; stream->stream_info.sfreq = substream->runtime->rate; - ret_val = stream->ops->stream_init(&stream->stream_info); + ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info); if (ret_val) pr_err("control_set ret error %d\n", ret_val); return ret_val; } -/* end -- helper functions */ static int sst_media_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -372,7 +371,7 @@ static void sst_media_close(struct snd_pcm_substream *substream, stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; if (str_id) - ret_val = stream->ops->close(str_id); + ret_val = stream->ops->close(sst->dev, str_id); module_put(sst->dev->driver->owner); kfree(stream); } @@ -402,7 +401,7 @@ static int sst_media_prepare(struct snd_pcm_substream *substream, stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; if (stream->stream_info.str_id) { - ret_val = stream->ops->stream_drop(str_id); + ret_val = stream->ops->stream_drop(sst->dev, str_id); return ret_val; } @@ -469,22 +468,22 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, pr_debug("sst: Trigger Start\n"); status = SST_PLATFORM_RUNNING; stream->stream_info.arg = substream; - ret_val = stream->ops->stream_start(str_id); + ret_val = stream->ops->stream_start(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_STOP: pr_debug("sst: in stop\n"); status = SST_PLATFORM_DROPPED; - ret_val = stream->ops->stream_drop(str_id); + ret_val = stream->ops->stream_drop(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: pr_debug("sst: in pause\n"); status = SST_PLATFORM_PAUSED; - ret_val = stream->ops->stream_pause(str_id); + ret_val = stream->ops->stream_pause(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: pr_debug("sst: in pause release\n"); status = SST_PLATFORM_RUNNING; - ret_val = stream->ops->stream_pause_release(str_id); + ret_val = stream->ops->stream_pause_release(sst->dev, str_id); break; default: return -EINVAL; @@ -509,7 +508,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer if (status == SST_PLATFORM_INIT) return 0; str_info = &stream->stream_info; - ret_val = stream->ops->stream_read_tstamp(str_info); + ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info); if (ret_val) { pr_err("sst: error code = %d\n", ret_val); return ret_val; diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 2d6e65bbbc49..d4c28b8fb471 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -113,15 +113,15 @@ struct compress_sst_ops { }; struct sst_ops { - int (*open) (struct snd_sst_params *str_param); - int (*stream_init) (struct pcm_stream_info *str_info); - int (*stream_start) (int str_id); - int (*stream_drop) (int str_id); - int (*stream_pause) (int str_id); - int (*stream_pause_release) (int str_id); - int (*stream_read_tstamp) (struct pcm_stream_info *str_info); - int (*send_byte_stream)(struct snd_sst_bytes_v2 *bytes); - int (*close) (unsigned int str_id); + int (*open) (struct device *dev, struct snd_sst_params *str_param); + int (*stream_init) (struct device *dev, struct pcm_stream_info *str_info); + int (*stream_start) (struct device *dev, int str_id); + int (*stream_drop) (struct device *dev, int str_id); + int (*stream_pause) (struct device *dev, int str_id); + int (*stream_pause_release) (struct device *dev, int str_id); + int (*stream_read_tstamp) (struct device *dev, struct pcm_stream_info *str_info); + int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes); + int (*close) (struct device *dev, unsigned int str_id); }; struct sst_runtime_stream { -- GitLab From d8499c9b4b03ca88d7c7b4094cb09471658df7c2 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 4 Aug 2014 15:15:55 +0530 Subject: [PATCH 0347/5088] ASoC: Intel: add mrfld DSP defines We define the DSP commands,structures here which will be used to send the IPCs Signed-off-by: Vinod Koul Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/Makefile | 3 +- sound/soc/intel/sst-atom-controls.c | 39 ++++ sound/soc/intel/sst-atom-controls.h | 286 +++++++++++++++++++++++- sound/soc/intel/sst-mfld-platform-pcm.c | 8 +- sound/soc/intel/sst-mfld-platform.h | 3 + 5 files changed, 335 insertions(+), 4 deletions(-) create mode 100644 sound/soc/intel/sst-atom-controls.c diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 7acbfc43a0c6..f841786dad15 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -2,7 +2,8 @@ snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o snd-soc-sst-acpi-objs := sst-acpi.o -snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o +snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ + sst-mfld-platform-compress.o sst-atom-controls.o snd-soc-mfld-machine-objs := mfld_machine.o obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c new file mode 100644 index 000000000000..ace3c4a59b14 --- /dev/null +++ b/sound/soc/intel/sst-atom-controls.c @@ -0,0 +1,39 @@ +/* + * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld + * + * Copyright (C) 2013-14 Intel Corp + * Author: Omair Mohammed Abdullah + * Vinod Koul + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include "sst-mfld-platform.h" +#include "sst-atom-controls.h" + +int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) +{ + int ret = 0; + struct sst_data *drv = snd_soc_platform_get_drvdata(platform); + + drv->byte_stream = devm_kzalloc(platform->dev, + SST_MAX_BIN_BYTES, GFP_KERNEL); + if (!drv->byte_stream) + return -ENOMEM; + + return ret; +} diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index 14063ab8c7c5..8554889c0694 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h @@ -1,4 +1,6 @@ /* + * sst-atom-controls.h - Intel MID Platform driver header file + * * Copyright (C) 2013-14 Intel Corp * Author: Ramesh Babu * Omair M Abdullah @@ -18,13 +20,293 @@ * */ -#ifndef __SST_CONTROLS_V2_H__ -#define __SST_CONTROLS_V2_H__ +#ifndef __SST_ATOM_CONTROLS_H__ +#define __SST_ATOM_CONTROLS_H__ enum { MERR_DPCM_AUDIO = 0, MERR_DPCM_COMPR, }; +/* define a bit for each mixer input */ +#define SST_MIX_IP(x) (x) + +#define SST_IP_CODEC0 SST_MIX_IP(2) +#define SST_IP_CODEC1 SST_MIX_IP(3) +#define SST_IP_LOOP0 SST_MIX_IP(4) +#define SST_IP_LOOP1 SST_MIX_IP(5) +#define SST_IP_LOOP2 SST_MIX_IP(6) +#define SST_IP_PROBE SST_MIX_IP(7) +#define SST_IP_VOIP SST_MIX_IP(12) +#define SST_IP_PCM0 SST_MIX_IP(13) +#define SST_IP_PCM1 SST_MIX_IP(14) +#define SST_IP_MEDIA0 SST_MIX_IP(17) +#define SST_IP_MEDIA1 SST_MIX_IP(18) +#define SST_IP_MEDIA2 SST_MIX_IP(19) +#define SST_IP_MEDIA3 SST_MIX_IP(20) + +#define SST_IP_LAST SST_IP_MEDIA3 + +#define SST_SWM_INPUT_COUNT (SST_IP_LAST + 1) +#define SST_CMD_SWM_MAX_INPUTS 6 + +#define SST_PATH_ID_SHIFT 8 +#define SST_DEFAULT_LOCATION_ID 0xFFFF +#define SST_DEFAULT_CELL_NBR 0xFF +#define SST_DEFAULT_MODULE_ID 0xFFFF + +/* + * Audio DSP Path Ids. Specified by the audio DSP FW + */ +enum sst_path_index { + SST_PATH_INDEX_CODEC_OUT0 = (0x02 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_CODEC_OUT1 = (0x03 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_SPROT_LOOP_OUT = (0x04 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP1_OUT = (0x05 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP2_OUT = (0x06 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_VOIP_OUT = (0x0C << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM0_OUT = (0x0D << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM1_OUT = (0x0E << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM2_OUT = (0x0F << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA0_OUT = (0x12 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA1_OUT = (0x13 << SST_PATH_ID_SHIFT), + + + /* Start of input paths */ + SST_PATH_INDEX_CODEC_IN0 = (0x82 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_CODEC_IN1 = (0x83 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_SPROT_LOOP_IN = (0x84 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP1_IN = (0x85 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP2_IN = (0x86 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_VOIP_IN = (0x8C << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_PCM0_IN = (0x8D << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM1_IN = (0x8E << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA0_IN = (0x8F << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA1_IN = (0x90 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA2_IN = (0x91 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA3_IN = (0x9C << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_RESERVED = (0xFF << SST_PATH_ID_SHIFT), +}; + +/* + * path IDs + */ +enum sst_swm_inputs { + SST_SWM_IN_CODEC0 = (SST_PATH_INDEX_CODEC_IN0 | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_CODEC1 = (SST_PATH_INDEX_CODEC_IN1 | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_VOIP = (SST_PATH_INDEX_VOIP_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_PCM0 = (SST_PATH_INDEX_PCM0_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_PCM1 = (SST_PATH_INDEX_PCM1_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA0 = (SST_PATH_INDEX_MEDIA0_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA1 = (SST_PATH_INDEX_MEDIA1_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA2 = (SST_PATH_INDEX_MEDIA2_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA3 = (SST_PATH_INDEX_MEDIA3_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR) +}; + +/* + * path IDs + */ +enum sst_swm_outputs { + SST_SWM_OUT_CODEC0 = (SST_PATH_INDEX_CODEC_OUT0 | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_CODEC1 = (SST_PATH_INDEX_CODEC_OUT1 | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_VOIP = (SST_PATH_INDEX_VOIP_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM0 = (SST_PATH_INDEX_PCM0_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM1 = (SST_PATH_INDEX_PCM1_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM2 = (SST_PATH_INDEX_PCM2_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA0 = (SST_PATH_INDEX_MEDIA0_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_OUT_MEDIA1 = (SST_PATH_INDEX_MEDIA1_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_OUT_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR), +}; + +enum sst_ipc_msg { + SST_IPC_IA_CMD = 1, + SST_IPC_IA_SET_PARAMS, + SST_IPC_IA_GET_PARAMS, +}; + +enum sst_cmd_type { + SST_CMD_BYTES_SET = 1, + SST_CMD_BYTES_GET = 2, +}; + +enum sst_task { + SST_TASK_SBA = 1, + SST_TASK_MMX, +}; + +enum sst_type { + SST_TYPE_CMD = 1, + SST_TYPE_PARAMS, +}; + +enum sst_flag { + SST_FLAG_BLOCKED = 1, + SST_FLAG_NONBLOCK, +}; + +/* + * Enumeration for indexing the gain cells in VB_SET_GAIN DSP command + */ +enum sst_gain_index { + /* GAIN IDs for SB task start here */ + SST_GAIN_INDEX_CODEC_OUT0, + SST_GAIN_INDEX_CODEC_OUT1, + SST_GAIN_INDEX_CODEC_IN0, + SST_GAIN_INDEX_CODEC_IN1, + + SST_GAIN_INDEX_SPROT_LOOP_OUT, + SST_GAIN_INDEX_MEDIA_LOOP1_OUT, + SST_GAIN_INDEX_MEDIA_LOOP2_OUT, + + SST_GAIN_INDEX_PCM0_IN_LEFT, + SST_GAIN_INDEX_PCM0_IN_RIGHT, + + SST_GAIN_INDEX_PCM1_OUT_LEFT, + SST_GAIN_INDEX_PCM1_OUT_RIGHT, + SST_GAIN_INDEX_PCM1_IN_LEFT, + SST_GAIN_INDEX_PCM1_IN_RIGHT, + SST_GAIN_INDEX_PCM2_OUT_LEFT, + + SST_GAIN_INDEX_PCM2_OUT_RIGHT, + SST_GAIN_INDEX_VOIP_OUT, + SST_GAIN_INDEX_VOIP_IN, + + /* Gain IDs for MMX task start here */ + SST_GAIN_INDEX_MEDIA0_IN_LEFT, + SST_GAIN_INDEX_MEDIA0_IN_RIGHT, + SST_GAIN_INDEX_MEDIA1_IN_LEFT, + SST_GAIN_INDEX_MEDIA1_IN_RIGHT, + + SST_GAIN_INDEX_MEDIA2_IN_LEFT, + SST_GAIN_INDEX_MEDIA2_IN_RIGHT, + + SST_GAIN_INDEX_GAIN_END +}; + +/* + * Audio DSP module IDs specified by FW spec + * TODO: Update with all modules + */ +enum sst_module_id { + SST_MODULE_ID_PCM = 0x0001, + SST_MODULE_ID_MP3 = 0x0002, + SST_MODULE_ID_MP24 = 0x0003, + SST_MODULE_ID_AAC = 0x0004, + SST_MODULE_ID_AACP = 0x0005, + SST_MODULE_ID_EAACP = 0x0006, + SST_MODULE_ID_WMA9 = 0x0007, + SST_MODULE_ID_WMA10 = 0x0008, + SST_MODULE_ID_WMA10P = 0x0009, + SST_MODULE_ID_RA = 0x000A, + SST_MODULE_ID_DDAC3 = 0x000B, + SST_MODULE_ID_TRUE_HD = 0x000C, + SST_MODULE_ID_HD_PLUS = 0x000D, + + SST_MODULE_ID_SRC = 0x0064, + SST_MODULE_ID_DOWNMIX = 0x0066, + SST_MODULE_ID_GAIN_CELL = 0x0067, + SST_MODULE_ID_SPROT = 0x006D, + SST_MODULE_ID_BASS_BOOST = 0x006E, + SST_MODULE_ID_STEREO_WDNG = 0x006F, + SST_MODULE_ID_AV_REMOVAL = 0x0070, + SST_MODULE_ID_MIC_EQ = 0x0071, + SST_MODULE_ID_SPL = 0x0072, + SST_MODULE_ID_ALGO_VTSV = 0x0073, + SST_MODULE_ID_NR = 0x0076, + SST_MODULE_ID_BWX = 0x0077, + SST_MODULE_ID_DRP = 0x0078, + SST_MODULE_ID_MDRP = 0x0079, + + SST_MODULE_ID_ANA = 0x007A, + SST_MODULE_ID_AEC = 0x007B, + SST_MODULE_ID_NR_SNS = 0x007C, + SST_MODULE_ID_SER = 0x007D, + SST_MODULE_ID_AGC = 0x007E, + + SST_MODULE_ID_CNI = 0x007F, + SST_MODULE_ID_CONTEXT_ALGO_AWARE = 0x0080, + SST_MODULE_ID_FIR_24 = 0x0081, + SST_MODULE_ID_IIR_24 = 0x0082, + + SST_MODULE_ID_ASRC = 0x0083, + SST_MODULE_ID_TONE_GEN = 0x0084, + SST_MODULE_ID_BMF = 0x0086, + SST_MODULE_ID_EDL = 0x0087, + SST_MODULE_ID_GLC = 0x0088, + + SST_MODULE_ID_FIR_16 = 0x0089, + SST_MODULE_ID_IIR_16 = 0x008A, + SST_MODULE_ID_DNR = 0x008B, + + SST_MODULE_ID_VIRTUALIZER = 0x008C, + SST_MODULE_ID_VISUALIZATION = 0x008D, + SST_MODULE_ID_LOUDNESS_OPTIMIZER = 0x008E, + SST_MODULE_ID_REVERBERATION = 0x008F, + + SST_MODULE_ID_CNI_TX = 0x0090, + SST_MODULE_ID_REF_LINE = 0x0091, + SST_MODULE_ID_VOLUME = 0x0092, + SST_MODULE_ID_FILT_DCR = 0x0094, + SST_MODULE_ID_SLV = 0x009A, + SST_MODULE_ID_NLF = 0x009B, + SST_MODULE_ID_TNR = 0x009C, + SST_MODULE_ID_WNR = 0x009D, + + SST_MODULE_ID_LOG = 0xFF00, + + SST_MODULE_ID_TASK = 0xFFFF, +}; + +enum sst_cmd { + SBA_IDLE = 14, + SBA_VB_SET_SPEECH_PATH = 26, + MMX_SET_GAIN = 33, + SBA_VB_SET_GAIN = 33, + FBA_VB_RX_CNI = 35, + MMX_SET_GAIN_TIMECONST = 36, + SBA_VB_SET_TIMECONST = 36, + SBA_VB_START = 85, + SBA_SET_SWM = 114, + SBA_SET_MDRP = 116, + SBA_HW_SET_SSP = 117, + SBA_SET_MEDIA_LOOP_MAP = 118, + SBA_SET_MEDIA_PATH = 119, + MMX_SET_MEDIA_PATH = 119, + SBA_VB_LPRO = 126, + SBA_VB_SET_FIR = 128, + SBA_VB_SET_IIR = 129, + SBA_SET_SSP_SLOT_MAP = 130, +}; + +enum sst_dsp_switch { + SST_SWITCH_OFF = 0, + SST_SWITCH_ON = 3, +}; + +enum sst_path_switch { + SST_PATH_OFF = 0, + SST_PATH_ON = 1, +}; + +enum sst_swm_state { + SST_SWM_OFF = 0, + SST_SWM_ON = 3, +}; #endif diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index a89ff7e18e1a..8e1e9bc27642 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -550,7 +550,13 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) return retval; } -static struct snd_soc_platform_driver sst_soc_platform_drv = { +static int sst_soc_probe(struct snd_soc_platform *platform) +{ + return sst_dsp_init_v2_dpcm(platform); +} + +static struct snd_soc_platform_driver sst_soc_platform_drv = { + .probe = sst_soc_probe, .ops = &sst_platform_ops, .compr_ops = &sst_platform_compr_ops, .pcm_new = sst_pcm_new, diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index d4c28b8fb471..faaba10c1dff 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -143,6 +143,8 @@ struct sst_device { }; struct sst_data; + +int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform); void sst_set_stream_status(struct sst_runtime_stream *stream, int state); int sst_fill_stream_params(void *substream, const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress); @@ -157,6 +159,7 @@ struct sst_algo_int_control_v2 { struct sst_data { struct platform_device *pdev; struct sst_platform_data *pdata; + char *byte_stream; struct mutex lock; }; int sst_register_dsp(struct sst_device *sst); -- GitLab From a493b6a637e9d8e828d7ed4be4bdf24dfd1f9250 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 8 Aug 2014 12:07:49 +0200 Subject: [PATCH 0348/5088] ASoC: rsnd: delete unneeded test before of_node_put MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Of_node_put supports NULL as its argument, so the initial test is not necessary. Suggested by Uwe Kleine-König. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression e; @@ -if (e) of_node_put(e); // Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 19f78963e8b9..1922ec57d10a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -798,10 +798,8 @@ if (name##_node) { \ mod_parse(src); mod_parse(dvc); - if (playback) - of_node_put(playback); - if (capture) - of_node_put(capture); + of_node_put(playback); + of_node_put(capture); } dai_i++; -- GitLab From 0d985b1c76623747107dbab1052044d6bac3866d Mon Sep 17 00:00:00 2001 From: Rongjun Ying Date: Wed, 13 Aug 2014 16:31:40 +0800 Subject: [PATCH 0349/5088] ASoC: sirf: usp: Add bitclock inversion support Signed-off-by: Rongjun Ying Signed-off-by: Mark Brown --- sound/soc/sirf/sirf-usp.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c index 3a730374e259..186dc7f33a55 100644 --- a/sound/soc/sirf/sirf-usp.c +++ b/sound/soc/sirf/sirf-usp.c @@ -100,6 +100,16 @@ static int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai, return -EINVAL; } + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + usp->daifmt_format |= (fmt & SND_SOC_DAIFMT_INV_MASK); + break; + default: + return -EINVAL; + } + return 0; } @@ -177,7 +187,7 @@ static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream, shifter_len = data_len; - switch (usp->daifmt_format) { + switch (usp->daifmt_format & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL, USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG); @@ -193,6 +203,18 @@ static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + switch (usp->daifmt_format & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + regmap_update_bits(usp->regmap, USP_MODE1, + USP_RXD_ACT_EDGE_FALLING | USP_TXD_ACT_EDGE_FALLING, + USP_RXD_ACT_EDGE_FALLING); + break; + default: + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL, USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK -- GitLab From a7a8e994ddd004fbabfcf04c26c204297b5f826d Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Fri, 1 Aug 2014 10:57:04 -0500 Subject: [PATCH 0350/5088] ASoC: tas2552: Add DAPM calls for amp and PLL Add DAPM calls to enable/disable the Class D amp. Also add a DAPM call to turn off the PLL upon the stream completing. Signed-off-by: Dan Murphy Signed-off-by: Mark Brown --- sound/soc/codecs/tas2552.c | 68 +++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 23b32960ff1d..1ed57a7e57b6 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -78,6 +78,43 @@ struct tas2552_data { unsigned int mclk; }; +/* Input mux controls */ +static const char *tas2552_input_texts[] = { + "Digital", "Analog" +}; + +static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7, + tas2552_input_texts); + +static const struct snd_kcontrol_new tas2552_input_mux_control[] = { + SOC_DAPM_ENUM("Input selection", tas2552_input_mux_enum) +}; + +static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] = +{ + SND_SOC_DAPM_INPUT("IN"), + + /* MUX Controls */ + SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0, + tas2552_input_mux_control), + + SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("OUT") +}; + +static const struct snd_soc_dapm_route tas2552_audio_map[] = { + {"DAC", NULL, "DAC IN"}, + {"Input selection", "Digital", "DAC"}, + {"Input selection", "Analog", "IN"}, + {"ClassD", NULL, "Input selection"}, + {"OUT", NULL, "ClassD"}, + {"ClassD", NULL, "PLL"}, +}; + static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown) { u8 cfg1_reg; @@ -101,10 +138,6 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream, int d; u8 p, j; - /* Turn on Class D amplifier */ - snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN_MASK, - TAS2552_CLASSD_EN); - if (!tas2552->mclk) return -EINVAL; @@ -147,9 +180,6 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream, } - snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, - TAS2552_PLL_ENABLE); - return 0; } @@ -269,19 +299,10 @@ static const struct dev_pm_ops tas2552_pm = { NULL) }; -static void tas2552_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - - snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0); -} - static struct snd_soc_dai_ops tas2552_speaker_dai_ops = { .hw_params = tas2552_hw_params, .set_sysclk = tas2552_set_dai_sysclk, .set_fmt = tas2552_set_dai_fmt, - .shutdown = tas2552_shutdown, .digital_mute = tas2552_mute, }; @@ -294,7 +315,7 @@ static struct snd_soc_dai_driver tas2552_dai[] = { { .name = "tas2552-amplifier", .playback = { - .stream_name = "Speaker", + .stream_name = "Playback", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, @@ -312,6 +333,7 @@ static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 24); static const struct snd_kcontrol_new tas2552_snd_controls[] = { SOC_SINGLE_TLV("Speaker Driver Playback Volume", TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv), + SOC_DAPM_SINGLE("Playback AMP", SND_SOC_NOPM, 0, 1, 0), }; static const struct reg_default tas2552_init_regs[] = { @@ -321,6 +343,7 @@ static const struct reg_default tas2552_init_regs[] = { static int tas2552_codec_probe(struct snd_soc_codec *codec) { struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; int ret; tas2552->codec = codec; @@ -362,9 +385,14 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec) goto patch_fail; } - snd_soc_write(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN | - TAS2552_BOOST_EN | TAS2552_APT_EN | - TAS2552_LIM_EN); + snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | + TAS2552_APT_EN | TAS2552_LIM_EN); + + snd_soc_dapm_new_controls(dapm, tas2552_dapm_widgets, + ARRAY_SIZE(tas2552_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, tas2552_audio_map, + ARRAY_SIZE(tas2552_audio_map)); + return 0; patch_fail: -- GitLab From dfe8f1f3f22f9922e773ae64f5621f290cb26023 Mon Sep 17 00:00:00 2001 From: Nikesh Oswal Date: Wed, 13 Aug 2014 10:05:45 +0100 Subject: [PATCH 0351/5088] ASoC: wm8994: Demux the microphone detection IRQ Current code only allows direct routing of the WM8994 microphone detection signal to a GPIO this change adds support to demux the interrupt from the main interrupt line of the codec. Signed-off-by: Nikesh Oswal Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 6cc0566dc29a..1fcb9f3f3097 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -4082,17 +4082,23 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) switch (control->type) { case WM8994: - if (wm8994->micdet_irq) { + if (wm8994->micdet_irq) ret = request_threaded_irq(wm8994->micdet_irq, NULL, wm8994_mic_irq, IRQF_TRIGGER_RISING, "Mic1 detect", wm8994); - if (ret != 0) - dev_warn(codec->dev, - "Failed to request Mic1 detect IRQ: %d\n", - ret); - } + else + ret = wm8994_request_irq(wm8994->wm8994, + WM8994_IRQ_MIC1_DET, + wm8994_mic_irq, "Mic 1 detect", + wm8994); + + if (ret != 0) + dev_warn(codec->dev, + "Failed to request Mic1 detect IRQ: %d\n", + ret); + ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_MIC1_SHRT, -- GitLab From d4f7facde1796c8b3eb2f79e1fd903d7b776972f Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 31 Jul 2014 10:43:35 +0800 Subject: [PATCH 0352/5088] devicetree: bindings: Add Everest Semicodunctor Everest Semiconductor makes audio codecs. Signed-off-by: Sean Cross 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 ac7269f90764..34cc1bfcebfd 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -48,6 +48,7 @@ epfl Ecole Polytechnique Fédérale de Lausanne epson Seiko Epson Corp. est ESTeem Wireless Modems eukrea Eukréa Electromatique +everest Everest Semiconductor Co. Ltd. excito Excito fsl Freescale Semiconductor GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. -- GitLab From 567e4f98922ce5542f8c2aa469a0c6ddf182b6ea Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 31 Jul 2014 10:43:36 +0800 Subject: [PATCH 0353/5088] ASoC: add es8328 codec driver Add a codec driver for the Everest ES8328. It supports two separate audio outputs and two separate audio inputs. Signed-off-by: Sean Cross Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/es8328.txt | 38 + sound/soc/codecs/Kconfig | 13 + sound/soc/codecs/Makefile | 6 + sound/soc/codecs/es8328-i2c.c | 60 ++ sound/soc/codecs/es8328-spi.c | 49 ++ sound/soc/codecs/es8328.c | 756 ++++++++++++++++++ sound/soc/codecs/es8328.h | 314 ++++++++ 7 files changed, 1236 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/es8328.txt create mode 100644 sound/soc/codecs/es8328-i2c.c create mode 100644 sound/soc/codecs/es8328-spi.c create mode 100644 sound/soc/codecs/es8328.c create mode 100644 sound/soc/codecs/es8328.h diff --git a/Documentation/devicetree/bindings/sound/es8328.txt b/Documentation/devicetree/bindings/sound/es8328.txt new file mode 100644 index 000000000000..30ea8a318ae9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/es8328.txt @@ -0,0 +1,38 @@ +Everest ES8328 audio CODEC + +This device supports both I2C and SPI. + +Required properties: + + - compatible : "everest,es8328" + - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V + - AVDD-supply : Regulator providing analog supply voltage 3.3V + - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V + - IPVDD-supply : Regulator providing analog output voltage 3.3V + - clocks : A 22.5792 or 11.2896 MHz clock + - reg : the I2C address of the device for I2C, the chip select number for SPI + +Pins on the device (for linking into audio routes): + + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * LINPUT1 + * RINPUT1 + * LINPUT2 + * RINPUT2 + * Mic Bias + + +Example: + +codec: es8328@11 { + compatible = "everest,es8328"; + DVDD-supply = <®_3p3v>; + AVDD-supply = <®_3p3v>; + PVDD-supply = <®_3p3v>; + HPVDD-supply = <®_3p3v>; + clocks = <&clks 169>; + reg = <0x11>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..8bca6343d8a3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -57,6 +57,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C select SND_SOC_BT_SCO + select SND_SOC_ES8328_SPI if SPI_MASTER + select SND_SOC_ES8328_I2C if I2C select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -405,6 +407,17 @@ config SND_SOC_DMIC config SND_SOC_HDMI_CODEC tristate "HDMI stub CODEC" +config SND_SOC_ES8328 + tristate "Everest Semi ES8328 CODEC" + +config SND_SOC_ES8328_I2C + tristate + select SND_SOC_ES8328 + +config SND_SOC_ES8328_SPI + tristate + select SND_SOC_ES8328 + config SND_SOC_ISABELLE tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 20afe0f0c5be..31a8283006d1 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -49,6 +49,9 @@ snd-soc-da732x-objs := da732x.o snd-soc-da9055-objs := da9055.o snd-soc-bt-sco-objs := bt-sco.o 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-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -220,6 +223,9 @@ obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o 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_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/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c new file mode 100644 index 000000000000..aae410d122ee --- /dev/null +++ b/sound/soc/codecs/es8328-i2c.c @@ -0,0 +1,60 @@ +/* + * es8328-i2c.c -- ES8328 ALSA SoC I2C Audio driver + * + * Copyright 2014 Sutajio Ko-Usagi PTE LTD + * + * Author: Sean Cross + * + * 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 "es8328.h" + +static const struct i2c_device_id es8328_id[] = { + { "everest,es8328", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, es8328_id); + +static const struct of_device_id es8328_of_match[] = { + { .compatible = "everest,es8328", }, + { } +}; +MODULE_DEVICE_TABLE(of, es8328_of_match); + +static int es8328_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + return es8328_probe(&i2c->dev, + devm_regmap_init_i2c(i2c, &es8328_regmap_config)); +} + +static int es8328_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + return 0; +} + +static struct i2c_driver es8328_i2c_driver = { + .driver = { + .name = "es8328", + .of_match_table = es8328_of_match, + }, + .probe = es8328_i2c_probe, + .remove = es8328_i2c_remove, + .id_table = es8328_id, +}; + +module_i2c_driver(es8328_i2c_driver); + +MODULE_DESCRIPTION("ASoC ES8328 audio CODEC I2C driver"); +MODULE_AUTHOR("Sean Cross "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8328-spi.c b/sound/soc/codecs/es8328-spi.c new file mode 100644 index 000000000000..8fbd935e1c76 --- /dev/null +++ b/sound/soc/codecs/es8328-spi.c @@ -0,0 +1,49 @@ +/* + * es8328.c -- ES8328 ALSA SoC SPI Audio driver + * + * Copyright 2014 Sutajio Ko-Usagi PTE LTD + * + * Author: Sean Cross + * + * 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 "es8328.h" + +static const struct of_device_id es8328_of_match[] = { + { .compatible = "everest,es8328", }, + { } +}; +MODULE_DEVICE_TABLE(of, es8328_of_match); + +static int es8328_spi_probe(struct spi_device *spi) +{ + return es8328_probe(&spi->dev, + devm_regmap_init_spi(spi, &es8328_regmap_config)); +} + +static int es8328_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + return 0; +} + +static struct spi_driver es8328_spi_driver = { + .driver = { + .name = "es8328", + .of_match_table = es8328_of_match, + }, + .probe = es8328_spi_probe, + .remove = es8328_spi_remove, +}; + +module_spi_driver(es8328_spi_driver); +MODULE_DESCRIPTION("ASoC ES8328 audio CODEC SPI driver"); +MODULE_AUTHOR("Sean Cross "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c new file mode 100644 index 000000000000..7a9f65ad183d --- /dev/null +++ b/sound/soc/codecs/es8328.c @@ -0,0 +1,756 @@ +/* + * es8328.c -- ES8328 ALSA SoC Audio driver + * + * Copyright 2014 Sutajio Ko-Usagi PTE LTD + * + * Author: Sean Cross + * + * 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 "es8328.h" + +#define ES8328_SYSCLK_RATE_1X 11289600 +#define ES8328_SYSCLK_RATE_2X 22579200 + +/* Run the codec at 22.5792 or 11.2896 MHz to support these rates */ +static struct { + int rate; + u8 ratio; +} mclk_ratios[] = { + { 8000, 9 }, + {11025, 7 }, + {22050, 4 }, + {44100, 2 }, +}; + +/* regulator supplies for sgtl5000, VDDD is an optional external supply */ +enum sgtl5000_regulator_supplies { + DVDD, + AVDD, + PVDD, + HPVDD, + ES8328_SUPPLY_NUM +}; + +/* vddd is optional supply */ +static const char * const supply_names[ES8328_SUPPLY_NUM] = { + "DVDD", + "AVDD", + "PVDD", + "HPVDD", +}; + +#define ES8328_RATES (SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_11025) +#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) + +struct es8328_priv { + struct regmap *regmap; + struct clk *clk; + int playback_fs; + bool deemph; + struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM]; +}; + +/* + * ES8328 Controls + */ + +static const char * const adcpol_txt[] = {"Normal", "L Invert", "R Invert", + "L + R Invert"}; +static SOC_ENUM_SINGLE_DECL(adcpol, + ES8328_ADCCONTROL6, 6, adcpol_txt); + +static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0); +static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0); +static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); +static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); +static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0); + +static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; + +static int es8328_set_deemph(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int val, i, best; + + /* + * If we're using deemphasis select the nearest available sample + * rate. + */ + if (es8328->deemph) { + best = 1; + for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { + if (abs(deemph_settings[i] - es8328->playback_fs) < + abs(deemph_settings[best] - es8328->playback_fs)) + best = i; + } + + val = best << 1; + } else { + val = 0; + } + + dev_dbg(codec->dev, "Set deemphasis %d\n", val); + + return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val); +} + +static int es8328_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = es8328->deemph; + return 0; +} + +static int es8328_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int deemph = ucontrol->value.enumerated.item[0]; + int ret; + + if (deemph > 1) + return -EINVAL; + + ret = es8328_set_deemph(codec); + if (ret < 0) + return ret; + + es8328->deemph = deemph; + + return 0; +} + + + +static const struct snd_kcontrol_new es8328_snd_controls[] = { + SOC_DOUBLE_R_TLV("Capture Digital Volume", + ES8328_ADCCONTROL8, ES8328_ADCCONTROL9, + 0, 0xc0, 1, dac_adc_tlv), + SOC_SINGLE("Capture ZC Switch", ES8328_ADCCONTROL7, 6, 1, 0), + + SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, + es8328_get_deemph, es8328_put_deemph), + + SOC_ENUM("Capture Polarity", adcpol), + + SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", + ES8328_DACCONTROL17, 3, 7, 1, bypass_tlv), + SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", + ES8328_DACCONTROL19, 3, 7, 1, bypass_tlv), + SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", + ES8328_DACCONTROL18, 3, 7, 1, bypass_tlv), + SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", + ES8328_DACCONTROL20, 3, 7, 1, bypass_tlv), + + SOC_DOUBLE_R_TLV("PCM Volume", + ES8328_LDACVOL, ES8328_RDACVOL, + 0, ES8328_DACVOL_MAX, 1, dac_adc_tlv), + + SOC_DOUBLE_R_TLV("Output 1 Playback Volume", + ES8328_LOUT1VOL, ES8328_ROUT1VOL, + 0, ES8328_OUT1VOL_MAX, 0, play_tlv), + + SOC_DOUBLE_R_TLV("Output 2 Playback Volume", + ES8328_LOUT2VOL, ES8328_ROUT2VOL, + 0, ES8328_OUT2VOL_MAX, 0, play_tlv), + + SOC_DOUBLE_TLV("Mic PGA Volume", ES8328_ADCCONTROL1, + 4, 0, 8, 0, mic_tlv), +}; + +/* + * DAPM Controls + */ + +static const char * const es8328_line_texts[] = { + "Line 1", "Line 2", "PGA", "Differential"}; + +static const struct soc_enum es8328_lline_enum = + SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 3, + ARRAY_SIZE(es8328_line_texts), + es8328_line_texts); +static const struct snd_kcontrol_new es8328_left_line_controls = + SOC_DAPM_ENUM("Route", es8328_lline_enum); + +static const struct soc_enum es8328_rline_enum = + SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 0, + ARRAY_SIZE(es8328_line_texts), + es8328_line_texts); +static const struct snd_kcontrol_new es8328_right_line_controls = + SOC_DAPM_ENUM("Route", es8328_lline_enum); + +/* Left Mixer */ +static const struct snd_kcontrol_new es8328_left_mixer_controls[] = { + SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0), + SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0), +}; + +/* Right Mixer */ +static const struct snd_kcontrol_new es8328_right_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0), + SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0), +}; + +static const char * const es8328_pga_sel[] = { + "Line 1", "Line 2", "Line 3", "Differential"}; + +/* Left PGA Mux */ +static const struct soc_enum es8328_lpga_enum = + SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 6, + ARRAY_SIZE(es8328_pga_sel), + es8328_pga_sel); +static const struct snd_kcontrol_new es8328_left_pga_controls = + SOC_DAPM_ENUM("Route", es8328_lpga_enum); + +/* Right PGA Mux */ +static const struct soc_enum es8328_rpga_enum = + SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 4, + ARRAY_SIZE(es8328_pga_sel), + es8328_pga_sel); +static const struct snd_kcontrol_new es8328_right_pga_controls = + SOC_DAPM_ENUM("Route", es8328_rpga_enum); + +/* Differential Mux */ +static const char * const es8328_diff_sel[] = {"Line 1", "Line 2"}; +static SOC_ENUM_SINGLE_DECL(diffmux, + ES8328_ADCCONTROL3, 7, es8328_diff_sel); +static const struct snd_kcontrol_new es8328_diffmux_controls = + SOC_DAPM_ENUM("Route", diffmux); + +/* Mono ADC Mux */ +static const char * const es8328_mono_mux[] = {"Stereo", "Mono (Left)", + "Mono (Right)", "Digital Mono"}; +static SOC_ENUM_SINGLE_DECL(monomux, + ES8328_ADCCONTROL3, 3, es8328_mono_mux); +static const struct snd_kcontrol_new es8328_monomux_controls = + SOC_DAPM_ENUM("Route", monomux); + +static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = { + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, + &es8328_diffmux_controls), + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, + &es8328_monomux_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, + &es8328_monomux_controls), + + SND_SOC_DAPM_MUX("Left PGA Mux", ES8328_ADCPOWER, + ES8328_ADCPOWER_AINL_OFF, 1, + &es8328_left_pga_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", ES8328_ADCPOWER, + ES8328_ADCPOWER_AINR_OFF, 1, + &es8328_right_pga_controls), + + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, + &es8328_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, + &es8328_right_line_controls), + + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8328_ADCPOWER, + ES8328_ADCPOWER_ADCR_OFF, 1), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8328_ADCPOWER, + ES8328_ADCPOWER_ADCL_OFF, 1), + + SND_SOC_DAPM_SUPPLY("Mic Bias", ES8328_ADCPOWER, + ES8328_ADCPOWER_MIC_BIAS_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Bias Gen", ES8328_ADCPOWER, + ES8328_ADCPOWER_ADC_BIAS_GEN_OFF, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC STM", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACSTM_RESET, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC STM", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCSTM_RESET, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC DIG", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACDIG_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC DIG", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCDIG_OFF, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC DLL", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACDLL_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC DLL", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCDLL_OFF, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("ADC Vref", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCVREF_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Vref", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACVREF_OFF, 1, NULL, 0), + + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8328_DACPOWER, + ES8328_DACPOWER_RDAC_OFF, 1), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER, + ES8328_DACPOWER_LDAC_OFF, 1), + + SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, + &es8328_left_mixer_controls[0], + ARRAY_SIZE(es8328_left_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, + &es8328_right_mixer_controls[0], + ARRAY_SIZE(es8328_right_mixer_controls)), + + SND_SOC_DAPM_PGA("Right Out 2", ES8328_DACPOWER, + ES8328_DACPOWER_ROUT2_ON, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", ES8328_DACPOWER, + ES8328_DACPOWER_LOUT2_ON, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", ES8328_DACPOWER, + ES8328_DACPOWER_ROUT1_ON, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", ES8328_DACPOWER, + ES8328_DACPOWER_LOUT1_ON, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + + SND_SOC_DAPM_INPUT("LINPUT1"), + SND_SOC_DAPM_INPUT("LINPUT2"), + SND_SOC_DAPM_INPUT("RINPUT1"), + SND_SOC_DAPM_INPUT("RINPUT2"), +}; + +static const struct snd_soc_dapm_route es8328_dapm_routes[] = { + + { "Left Line Mux", "Line 1", "LINPUT1" }, + { "Left Line Mux", "Line 2", "LINPUT2" }, + { "Left Line Mux", "PGA", "Left PGA Mux" }, + { "Left Line Mux", "Differential", "Differential Mux" }, + + { "Right Line Mux", "Line 1", "RINPUT1" }, + { "Right Line Mux", "Line 2", "RINPUT2" }, + { "Right Line Mux", "PGA", "Right PGA Mux" }, + { "Right Line Mux", "Differential", "Differential Mux" }, + + { "Left PGA Mux", "Line 1", "LINPUT1" }, + { "Left PGA Mux", "Line 2", "LINPUT2" }, + { "Left PGA Mux", "Differential", "Differential Mux" }, + + { "Right PGA Mux", "Line 1", "RINPUT1" }, + { "Right PGA Mux", "Line 2", "RINPUT2" }, + { "Right PGA Mux", "Differential", "Differential Mux" }, + + { "Differential Mux", "Line 1", "LINPUT1" }, + { "Differential Mux", "Line 1", "RINPUT1" }, + { "Differential Mux", "Line 2", "LINPUT2" }, + { "Differential Mux", "Line 2", "RINPUT2" }, + + { "Left ADC Mux", "Stereo", "Left PGA Mux" }, + { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" }, + { "Left ADC Mux", "Digital Mono", "Left PGA Mux" }, + + { "Right ADC Mux", "Stereo", "Right PGA Mux" }, + { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" }, + { "Right ADC Mux", "Digital Mono", "Right PGA Mux" }, + + { "Left ADC", NULL, "Left ADC Mux" }, + { "Right ADC", NULL, "Right ADC Mux" }, + + { "ADC DIG", NULL, "ADC STM" }, + { "ADC DIG", NULL, "ADC Vref" }, + { "ADC DIG", NULL, "ADC DLL" }, + + { "Left ADC", NULL, "ADC DIG" }, + { "Right ADC", NULL, "ADC DIG" }, + + { "Mic Bias", NULL, "Mic Bias Gen" }, + + { "Left Line Mux", "Line 1", "LINPUT1" }, + { "Left Line Mux", "Line 2", "LINPUT2" }, + { "Left Line Mux", "PGA", "Left PGA Mux" }, + { "Left Line Mux", "Differential", "Differential Mux" }, + + { "Right Line Mux", "Line 1", "RINPUT1" }, + { "Right Line Mux", "Line 2", "RINPUT2" }, + { "Right Line Mux", "PGA", "Right PGA Mux" }, + { "Right Line Mux", "Differential", "Differential Mux" }, + + { "Left Out 1", NULL, "Left DAC" }, + { "Right Out 1", NULL, "Right DAC" }, + { "Left Out 2", NULL, "Left DAC" }, + { "Right Out 2", NULL, "Right DAC" }, + + { "Left Mixer", "Playback Switch", "Left DAC" }, + { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, + { "Left Mixer", "Right Playback Switch", "Right DAC" }, + { "Left Mixer", "Right Bypass Switch", "Right Line Mux" }, + + { "Right Mixer", "Left Playback Switch", "Left DAC" }, + { "Right Mixer", "Left Bypass Switch", "Left Line Mux" }, + { "Right Mixer", "Playback Switch", "Right DAC" }, + { "Right Mixer", "Right Bypass Switch", "Right Line Mux" }, + + { "DAC DIG", NULL, "DAC STM" }, + { "DAC DIG", NULL, "DAC Vref" }, + { "DAC DIG", NULL, "DAC DLL" }, + + { "Left DAC", NULL, "DAC DIG" }, + { "Right DAC", NULL, "DAC DIG" }, + + { "Left Out 1", NULL, "Left Mixer" }, + { "LOUT1", NULL, "Left Out 1" }, + { "Right Out 1", NULL, "Right Mixer" }, + { "ROUT1", NULL, "Right Out 1" }, + + { "Left Out 2", NULL, "Left Mixer" }, + { "LOUT2", NULL, "Left Out 2" }, + { "Right Out 2", NULL, "Right Mixer" }, + { "ROUT2", NULL, "Right Out 2" }, +}; + +static int es8328_mute(struct snd_soc_dai *dai, int mute) +{ + return snd_soc_update_bits(dai->codec, ES8328_DACCONTROL3, + ES8328_DACCONTROL3_DACMUTE, + mute ? ES8328_DACCONTROL3_DACMUTE : 0); +} + +static int es8328_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 es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int clk_rate; + int i; + int reg; + u8 ratio; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + reg = ES8328_DACCONTROL2; + else + reg = ES8328_ADCCONTROL5; + + clk_rate = clk_get_rate(es8328->clk); + + if ((clk_rate != ES8328_SYSCLK_RATE_1X) && + (clk_rate != ES8328_SYSCLK_RATE_2X)) { + dev_err(codec->dev, + "%s: clock is running at %d Hz, not %d or %d Hz\n", + __func__, clk_rate, + ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X); + return -EINVAL; + } + + /* find master mode MCLK to sampling frequency ratio */ + ratio = mclk_ratios[0].rate; + for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++) + if (params_rate(params) <= mclk_ratios[i].rate) + ratio = mclk_ratios[i].ratio; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + es8328->playback_fs = params_rate(params); + es8328_set_deemph(codec); + } + + return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio); +} + +static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int clk_rate; + u8 mode = ES8328_DACCONTROL1_DACWL_16; + + /* set master/slave audio interface */ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM) + return -EINVAL; + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + mode |= ES8328_DACCONTROL1_DACFORMAT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST; + break; + case SND_SOC_DAIFMT_LEFT_J: + mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) + return -EINVAL; + + snd_soc_write(codec, ES8328_DACCONTROL1, mode); + snd_soc_write(codec, ES8328_ADCCONTROL4, mode); + + /* Master serial port mode, with BCLK generated automatically */ + clk_rate = clk_get_rate(es8328->clk); + if (clk_rate == ES8328_SYSCLK_RATE_1X) + snd_soc_write(codec, ES8328_MASTERMODE, + ES8328_MASTERMODE_MSC); + else + snd_soc_write(codec, ES8328_MASTERMODE, + ES8328_MASTERMODE_MCLKDIV2 | + ES8328_MASTERMODE_MSC); + + return 0; +} + +static int es8328_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* VREF, VMID=2x50k, digital enabled */ + snd_soc_write(codec, ES8328_CHIPPOWER, 0); + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + ES8328_CONTROL1_VMIDSEL_50k | + ES8328_CONTROL1_ENREF); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + ES8328_CONTROL1_VMIDSEL_5k | + ES8328_CONTROL1_ENREF); + + /* Charge caps */ + msleep(100); + } + + snd_soc_write(codec, ES8328_CONTROL2, + ES8328_CONTROL2_OVERCURRENT_ON | + ES8328_CONTROL2_THERMAL_SHUTDOWN_ON); + + /* VREF, VMID=2*500k, digital stopped */ + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + ES8328_CONTROL1_VMIDSEL_500k | + ES8328_CONTROL1_ENREF); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + 0); + break; + } + codec->dapm.bias_level = level; + return 0; +} + +static const struct snd_soc_dai_ops es8328_dai_ops = { + .hw_params = es8328_hw_params, + .digital_mute = es8328_mute, + .set_fmt = es8328_set_dai_fmt, +}; + +static struct snd_soc_dai_driver es8328_dai = { + .name = "es8328-hifi-analog", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = ES8328_RATES, + .formats = ES8328_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = ES8328_RATES, + .formats = ES8328_FORMATS, + }, + .ops = &es8328_dai_ops, +}; + +static int es8328_suspend(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328; + int ret; + + es8328 = snd_soc_codec_get_drvdata(codec); + + es8328_set_bias_level(codec, SND_SOC_BIAS_OFF); + + clk_disable_unprepare(es8328->clk); + + ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(codec->dev, "unable to disable regulators\n"); + return ret; + } + return 0; +} + +static int es8328_resume(struct snd_soc_codec *codec) +{ + struct regmap *regmap = dev_get_regmap(codec->dev, NULL); + struct es8328_priv *es8328; + int ret; + + es8328 = snd_soc_codec_get_drvdata(codec); + + ret = clk_prepare_enable(es8328->clk); + if (ret) { + dev_err(codec->dev, "unable to enable clock\n"); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(codec->dev, "unable to enable regulators\n"); + return ret; + } + + regcache_mark_dirty(regmap); + ret = regcache_sync(regmap); + if (ret) { + dev_err(codec->dev, "unable to sync regcache\n"); + return ret; + } + + es8328_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; +} + +static int es8328_codec_probe(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328; + int ret; + + es8328 = snd_soc_codec_get_drvdata(codec); + + ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(codec->dev, "unable to enable regulators\n"); + return ret; + } + + /* Setup clocks */ + es8328->clk = devm_clk_get(codec->dev, NULL); + if (IS_ERR(es8328->clk)) { + dev_err(codec->dev, "codec clock missing or invalid\n"); + goto clk_fail; + } + + ret = clk_prepare_enable(es8328->clk); + if (ret) { + dev_err(codec->dev, "unable to prepare codec clk\n"); + goto clk_fail; + } + + return 0; + +clk_fail: + regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + return ret; +} + +static int es8328_remove(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328; + + es8328 = snd_soc_codec_get_drvdata(codec); + + if (es8328->clk) + clk_disable_unprepare(es8328->clk); + + regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + + return 0; +} + +const struct regmap_config es8328_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ES8328_REG_MAX, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(es8328_regmap_config); + +static struct snd_soc_codec_driver es8328_codec_driver = { + .probe = es8328_codec_probe, + .suspend = es8328_suspend, + .resume = es8328_resume, + .remove = es8328_remove, + .set_bias_level = es8328_set_bias_level, + .controls = es8328_snd_controls, + .num_controls = ARRAY_SIZE(es8328_snd_controls), + .dapm_widgets = es8328_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets), + .dapm_routes = es8328_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8328_dapm_routes), +}; + +int es8328_probe(struct device *dev, struct regmap *regmap) +{ + struct es8328_priv *es8328; + int ret; + int i; + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + es8328 = devm_kzalloc(dev, sizeof(*es8328), GFP_KERNEL); + if (es8328 == NULL) + return -ENOMEM; + + es8328->regmap = regmap; + + for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++) + es8328->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(dev, "unable to get regulators\n"); + return ret; + } + + dev_set_drvdata(dev, es8328); + + return snd_soc_register_codec(dev, + &es8328_codec_driver, &es8328_dai, 1); +} +EXPORT_SYMBOL_GPL(es8328_probe); + +MODULE_DESCRIPTION("ASoC ES8328 driver"); +MODULE_AUTHOR("Sean Cross "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h new file mode 100644 index 000000000000..cb36afe10c0e --- /dev/null +++ b/sound/soc/codecs/es8328.h @@ -0,0 +1,314 @@ +/* + * es8328.h -- ES8328 ALSA SoC Audio driver + */ + +#ifndef _ES8328_H +#define _ES8328_H + +#include + +struct device; + +extern const struct regmap_config es8328_regmap_config; +int es8328_probe(struct device *dev, struct regmap *regmap); + +#define ES8328_DACLVOL 46 +#define ES8328_DACRVOL 47 +#define ES8328_DACCTL 28 +#define ES8328_RATEMASK (0x1f << 0) + +#define ES8328_CONTROL1 0x00 +#define ES8328_CONTROL1_VMIDSEL_OFF (0 << 0) +#define ES8328_CONTROL1_VMIDSEL_50k (1 << 0) +#define ES8328_CONTROL1_VMIDSEL_500k (2 << 0) +#define ES8328_CONTROL1_VMIDSEL_5k (3 << 0) +#define ES8328_CONTROL1_VMIDSEL_MASK (7 << 0) +#define ES8328_CONTROL1_ENREF (1 << 2) +#define ES8328_CONTROL1_SEQEN (1 << 3) +#define ES8328_CONTROL1_SAMEFS (1 << 4) +#define ES8328_CONTROL1_DACMCLK_ADC (0 << 5) +#define ES8328_CONTROL1_DACMCLK_DAC (1 << 5) +#define ES8328_CONTROL1_LRCM (1 << 6) +#define ES8328_CONTROL1_SCP_RESET (1 << 7) + +#define ES8328_CONTROL2 0x01 +#define ES8328_CONTROL2_VREF_BUF_OFF (1 << 0) +#define ES8328_CONTROL2_VREF_LOWPOWER (1 << 1) +#define ES8328_CONTROL2_IBIASGEN_OFF (1 << 2) +#define ES8328_CONTROL2_ANALOG_OFF (1 << 3) +#define ES8328_CONTROL2_VREF_BUF_LOWPOWER (1 << 4) +#define ES8328_CONTROL2_VCM_MOD_LOWPOWER (1 << 5) +#define ES8328_CONTROL2_OVERCURRENT_ON (1 << 6) +#define ES8328_CONTROL2_THERMAL_SHUTDOWN_ON (1 << 7) + +#define ES8328_CHIPPOWER 0x02 +#define ES8328_CHIPPOWER_DACVREF_OFF 0 +#define ES8328_CHIPPOWER_ADCVREF_OFF 1 +#define ES8328_CHIPPOWER_DACDLL_OFF 2 +#define ES8328_CHIPPOWER_ADCDLL_OFF 3 +#define ES8328_CHIPPOWER_DACSTM_RESET 4 +#define ES8328_CHIPPOWER_ADCSTM_RESET 5 +#define ES8328_CHIPPOWER_DACDIG_OFF 6 +#define ES8328_CHIPPOWER_ADCDIG_OFF 7 + +#define ES8328_ADCPOWER 0x03 +#define ES8328_ADCPOWER_INT1_LOWPOWER 0 +#define ES8328_ADCPOWER_FLASH_ADC_LOWPOWER 1 +#define ES8328_ADCPOWER_ADC_BIAS_GEN_OFF 2 +#define ES8328_ADCPOWER_MIC_BIAS_OFF 3 +#define ES8328_ADCPOWER_ADCR_OFF 4 +#define ES8328_ADCPOWER_ADCL_OFF 5 +#define ES8328_ADCPOWER_AINR_OFF 6 +#define ES8328_ADCPOWER_AINL_OFF 7 + +#define ES8328_DACPOWER 0x04 +#define ES8328_DACPOWER_OUT3_ON 0 +#define ES8328_DACPOWER_MONO_ON 1 +#define ES8328_DACPOWER_ROUT2_ON 2 +#define ES8328_DACPOWER_LOUT2_ON 3 +#define ES8328_DACPOWER_ROUT1_ON 4 +#define ES8328_DACPOWER_LOUT1_ON 5 +#define ES8328_DACPOWER_RDAC_OFF 6 +#define ES8328_DACPOWER_LDAC_OFF 7 + +#define ES8328_CHIPLOPOW1 0x05 +#define ES8328_CHIPLOPOW2 0x06 +#define ES8328_ANAVOLMANAG 0x07 + +#define ES8328_MASTERMODE 0x08 +#define ES8328_MASTERMODE_BCLKDIV (0 << 0) +#define ES8328_MASTERMODE_BCLK_INV (1 << 5) +#define ES8328_MASTERMODE_MCLKDIV2 (1 << 6) +#define ES8328_MASTERMODE_MSC (1 << 7) + +#define ES8328_ADCCONTROL1 0x09 +#define ES8328_ADCCONTROL2 0x0a +#define ES8328_ADCCONTROL3 0x0b +#define ES8328_ADCCONTROL4 0x0c +#define ES8328_ADCCONTROL5 0x0d +#define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0) + +#define ES8328_ADCCONTROL6 0x0e + +#define ES8328_ADCCONTROL7 0x0f +#define ES8328_ADCCONTROL7_ADC_MUTE (1 << 2) +#define ES8328_ADCCONTROL7_ADC_LER (1 << 3) +#define ES8328_ADCCONTROL7_ADC_ZERO_CROSS (1 << 4) +#define ES8328_ADCCONTROL7_ADC_SOFT_RAMP (1 << 5) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_4 (0 << 6) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_8 (1 << 6) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_16 (2 << 6) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_32 (3 << 6) + +#define ES8328_ADCCONTROL8 0x10 +#define ES8328_ADCCONTROL9 0x11 +#define ES8328_ADCCONTROL10 0x12 +#define ES8328_ADCCONTROL11 0x13 +#define ES8328_ADCCONTROL12 0x14 +#define ES8328_ADCCONTROL13 0x15 +#define ES8328_ADCCONTROL14 0x16 + +#define ES8328_DACCONTROL1 0x17 +#define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1) +#define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1) +#define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1) +#define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1) +#define ES8328_DACCONTROL1_DACWL_24 (0 << 3) +#define ES8328_DACCONTROL1_DACWL_20 (1 << 3) +#define ES8328_DACCONTROL1_DACWL_18 (2 << 3) +#define ES8328_DACCONTROL1_DACWL_16 (3 << 3) +#define ES8328_DACCONTROL1_DACWL_32 (4 << 3) +#define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6) +#define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6) +#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6) +#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK1 (1 << 6) +#define ES8328_DACCONTROL1_LRSWAP (1 << 7) + +#define ES8328_DACCONTROL2 0x18 +#define ES8328_DACCONTROL2_RATEMASK (0x1f << 0) +#define ES8328_DACCONTROL2_DOUBLESPEED (1 << 5) + +#define ES8328_DACCONTROL3 0x19 +#define ES8328_DACCONTROL3_AUTOMUTE (1 << 2) +#define ES8328_DACCONTROL3_DACMUTE (1 << 2) +#define ES8328_DACCONTROL3_LEFTGAINVOL (1 << 3) +#define ES8328_DACCONTROL3_DACZEROCROSS (1 << 4) +#define ES8328_DACCONTROL3_DACSOFTRAMP (1 << 5) +#define ES8328_DACCONTROL3_DACRAMPRATE (3 << 6) + +#define ES8328_LDACVOL 0x1a +#define ES8328_LDACVOL_MASK (0 << 0) +#define ES8328_LDACVOL_MAX (0xc0) + +#define ES8328_RDACVOL 0x1b +#define ES8328_RDACVOL_MASK (0 << 0) +#define ES8328_RDACVOL_MAX (0xc0) + +#define ES8328_DACVOL_MAX (0xc0) + +#define ES8328_DACCONTROL4 0x1a +#define ES8328_DACCONTROL5 0x1b + +#define ES8328_DACCONTROL6 0x1c +#define ES8328_DACCONTROL6_CLICKFREE (1 << 3) +#define ES8328_DACCONTROL6_DAC_INVR (1 << 4) +#define ES8328_DACCONTROL6_DAC_INVL (1 << 5) +#define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6) +#define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6) +#define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6) +#define ES8328_DACCONTROL6_DEEMPH_48k (3 << 6) + +#define ES8328_DACCONTROL7 0x1d +#define ES8328_DACCONTROL7_VPP_SCALE_3p5 (0 << 0) +#define ES8328_DACCONTROL7_VPP_SCALE_4p0 (1 << 0) +#define ES8328_DACCONTROL7_VPP_SCALE_3p0 (2 << 0) +#define ES8328_DACCONTROL7_VPP_SCALE_2p5 (3 << 0) +#define ES8328_DACCONTROL7_SHELVING_STRENGTH (1 << 2) /* In eights */ +#define ES8328_DACCONTROL7_MONO (1 << 5) +#define ES8328_DACCONTROL7_ZEROR (1 << 6) +#define ES8328_DACCONTROL7_ZEROL (1 << 7) + +/* Shelving filter */ +#define ES8328_DACCONTROL8 0x1e +#define ES8328_DACCONTROL9 0x1f +#define ES8328_DACCONTROL10 0x20 +#define ES8328_DACCONTROL11 0x21 +#define ES8328_DACCONTROL12 0x22 +#define ES8328_DACCONTROL13 0x23 +#define ES8328_DACCONTROL14 0x24 +#define ES8328_DACCONTROL15 0x25 + +#define ES8328_DACCONTROL16 0x26 +#define ES8328_DACCONTROL16_RMIXSEL_RIN1 (0 << 0) +#define ES8328_DACCONTROL16_RMIXSEL_RIN2 (1 << 0) +#define ES8328_DACCONTROL16_RMIXSEL_RIN3 (2 << 0) +#define ES8328_DACCONTROL16_RMIXSEL_RADC (3 << 0) +#define ES8328_DACCONTROL16_LMIXSEL_LIN1 (0 << 3) +#define ES8328_DACCONTROL16_LMIXSEL_LIN2 (1 << 3) +#define ES8328_DACCONTROL16_LMIXSEL_LIN3 (2 << 3) +#define ES8328_DACCONTROL16_LMIXSEL_LADC (3 << 3) + +#define ES8328_DACCONTROL17 0x27 +#define ES8328_DACCONTROL17_LI2LOVOL (7 << 3) +#define ES8328_DACCONTROL17_LI2LO (1 << 6) +#define ES8328_DACCONTROL17_LD2LO (1 << 7) + +#define ES8328_DACCONTROL18 0x28 +#define ES8328_DACCONTROL18_RI2LOVOL (7 << 3) +#define ES8328_DACCONTROL18_RI2LO (1 << 6) +#define ES8328_DACCONTROL18_RD2LO (1 << 7) + +#define ES8328_DACCONTROL19 0x29 +#define ES8328_DACCONTROL19_LI2ROVOL (7 << 3) +#define ES8328_DACCONTROL19_LI2RO (1 << 6) +#define ES8328_DACCONTROL19_LD2RO (1 << 7) + +#define ES8328_DACCONTROL20 0x2a +#define ES8328_DACCONTROL20_RI2ROVOL (7 << 3) +#define ES8328_DACCONTROL20_RI2RO (1 << 6) +#define ES8328_DACCONTROL20_RD2RO (1 << 7) + +#define ES8328_DACCONTROL21 0x2b +#define ES8328_DACCONTROL21_LI2MOVOL (7 << 3) +#define ES8328_DACCONTROL21_LI2MO (1 << 6) +#define ES8328_DACCONTROL21_LD2MO (1 << 7) + +#define ES8328_DACCONTROL22 0x2c +#define ES8328_DACCONTROL22_RI2MOVOL (7 << 3) +#define ES8328_DACCONTROL22_RI2MO (1 << 6) +#define ES8328_DACCONTROL22_RD2MO (1 << 7) + +#define ES8328_DACCONTROL23 0x2d +#define ES8328_DACCONTROL23_MOUTINV (1 << 1) +#define ES8328_DACCONTROL23_HPSWPOL (1 << 2) +#define ES8328_DACCONTROL23_HPSWEN (1 << 3) +#define ES8328_DACCONTROL23_VROI_1p5k (0 << 4) +#define ES8328_DACCONTROL23_VROI_40k (1 << 4) +#define ES8328_DACCONTROL23_OUT3_VREF (0 << 5) +#define ES8328_DACCONTROL23_OUT3_ROUT1 (1 << 5) +#define ES8328_DACCONTROL23_OUT3_MONOOUT (2 << 5) +#define ES8328_DACCONTROL23_OUT3_RIGHT_MIXER (3 << 5) +#define ES8328_DACCONTROL23_ROUT2INV (1 << 7) + +/* LOUT1 Amplifier */ +#define ES8328_LOUT1VOL 0x2e +#define ES8328_LOUT1VOL_MASK (0 << 5) +#define ES8328_LOUT1VOL_MAX (0x24) + +/* ROUT1 Amplifier */ +#define ES8328_ROUT1VOL 0x2f +#define ES8328_ROUT1VOL_MASK (0 << 5) +#define ES8328_ROUT1VOL_MAX (0x24) + +#define ES8328_OUT1VOL_MAX (0x24) + +/* LOUT2 Amplifier */ +#define ES8328_LOUT2VOL 0x30 +#define ES8328_LOUT2VOL_MASK (0 << 5) +#define ES8328_LOUT2VOL_MAX (0x24) + +/* ROUT2 Amplifier */ +#define ES8328_ROUT2VOL 0x31 +#define ES8328_ROUT2VOL_MASK (0 << 5) +#define ES8328_ROUT2VOL_MAX (0x24) + +#define ES8328_OUT2VOL_MAX (0x24) + +/* Mono Out Amplifier */ +#define ES8328_MONOOUTVOL 0x32 +#define ES8328_MONOOUTVOL_MASK (0 << 5) +#define ES8328_MONOOUTVOL_MAX (0x24) + +#define ES8328_DACCONTROL29 0x33 +#define ES8328_DACCONTROL30 0x34 + +#define ES8328_SYSCLK 0 + +#define ES8328_REG_MAX 0x35 + +#define ES8328_PLL1 0 +#define ES8328_PLL2 1 + +/* clock inputs */ +#define ES8328_MCLK 0 +#define ES8328_PCMCLK 1 + +/* clock divider id's */ +#define ES8328_PCMDIV 0 +#define ES8328_BCLKDIV 1 +#define ES8328_VXCLKDIV 2 + +/* PCM clock dividers */ +#define ES8328_PCM_DIV_1 (0 << 6) +#define ES8328_PCM_DIV_3 (2 << 6) +#define ES8328_PCM_DIV_5_5 (3 << 6) +#define ES8328_PCM_DIV_2 (4 << 6) +#define ES8328_PCM_DIV_4 (5 << 6) +#define ES8328_PCM_DIV_6 (6 << 6) +#define ES8328_PCM_DIV_8 (7 << 6) + +/* BCLK clock dividers */ +#define ES8328_BCLK_DIV_1 (0 << 7) +#define ES8328_BCLK_DIV_2 (1 << 7) +#define ES8328_BCLK_DIV_4 (2 << 7) +#define ES8328_BCLK_DIV_8 (3 << 7) + +/* VXCLK clock dividers */ +#define ES8328_VXCLK_DIV_1 (0 << 6) +#define ES8328_VXCLK_DIV_2 (1 << 6) +#define ES8328_VXCLK_DIV_4 (2 << 6) +#define ES8328_VXCLK_DIV_8 (3 << 6) +#define ES8328_VXCLK_DIV_16 (4 << 6) + +#define ES8328_DAI_HIFI 0 +#define ES8328_DAI_VOICE 1 + +#define ES8328_1536FS 1536 +#define ES8328_1024FS 1024 +#define ES8328_768FS 768 +#define ES8328_512FS 512 +#define ES8328_384FS 384 +#define ES8328_256FS 256 +#define ES8328_128FS 128 + +#endif -- GitLab From 7e7292dba2155c1433ce9f9a819f1acb9090747b Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 31 Jul 2014 10:43:37 +0800 Subject: [PATCH 0354/5088] ASoC: fsl: add imx-es8328 machine driver This adds an initial machine driver for the ES8328 audio codec on Freescale boards. The driver supports headphones and an audio regulator for an onboard speaker amp. Signed-off-by: Sean Cross Signed-off-by: Mark Brown --- .../bindings/sound/imx-audio-es8328.txt | 60 +++++ sound/soc/fsl/Kconfig | 14 ++ sound/soc/fsl/Makefile | 2 + sound/soc/fsl/imx-es8328.c | 232 ++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/imx-audio-es8328.txt create mode 100644 sound/soc/fsl/imx-es8328.c diff --git a/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt new file mode 100644 index 000000000000..07b68ab206fb --- /dev/null +++ b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt @@ -0,0 +1,60 @@ +Freescale i.MX audio complex with ES8328 codec + +Required properties: +- compatible : "fsl,imx-audio-es8328" +- model : The user-visible name of this sound complex +- ssi-controller : The phandle of the i.MX SSI controller +- jack-gpio : Optional GPIO for headphone jack +- audio-amp-supply : Power regulator for speaker amps +- audio-codec : The phandle of the ES8328 audio codec +- 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 could be power supplies, ES8328 + pins, and the jacks on the board: + + Power supplies: + * audio-amp + + ES8328 pins: + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * LINPUT1 + * LINPUT2 + * RINPUT1 + * RINPUT2 + * Mic PGA + + Board connectors: + * Headphone + * Speaker + * Mic Jack +- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) +- mux-ext-port : The external port of the i.MX audio muxer (AUDMIX) + +Note: The AUDMUX port numbering should start at 1, which is consistent with +hardware manual. + +Example: + +sound { + compatible = "fsl,imx-audio-es8328"; + model = "imx-audio-es8328"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + jack-gpio = <&gpio5 15 0>; + audio-amp-supply = <®_audio_amp>; + audio-routing = + "Speaker", "LOUT2", + "Speaker", "ROUT2", + "Speaker", "audio-amp", + "Headphone", "ROUT1", + "Headphone", "LOUT1", + "LINPUT1", "Mic Jack", + "RINPUT1", "Mic Jack", + "Mic Jack", "Mic Bias"; + mux-int-port = <1>; + mux-ext-port = <3>; +}; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 2b99a9e86899..fa90340dc13a 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -257,6 +257,20 @@ config SND_SOC_IMX_WM8962 Say Y if you want to add support for SoC audio on an i.MX board with a wm8962 codec. +config SND_SOC_IMX_ES8328 + tristate "SoC Audio support for i.MX boards with the ES8328 codec" + depends on OF && (I2C || SPI) + select SND_SOC_ES8328_I2C if I2C + select SND_SOC_ES8328_SPI if SPI_MASTER + select SND_SOC_IMX_PCM_DMA + select SND_SOC_IMX_AUDMUX + select SND_SOC_FSL_SSI + select SND_SOC_FSL_UTILS + select SND_SOC_IMX_PCM_FIQ + help + Say Y if you want to add support for the ES8328 audio codec connected + via SSI/I2S over either SPI or I2C. + config SND_SOC_IMX_SGTL5000 tristate "SoC Audio support for i.MX boards with sgtl5000" depends on OF && I2C diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 8f6d84efa973..d28dc25c9375 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -52,6 +52,7 @@ snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o snd-soc-phycore-ac97-objs := phycore-ac97.o snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o snd-soc-wm1133-ev1-objs := wm1133-ev1.o +snd-soc-imx-es8328-objs := imx-es8328.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-wm8962-objs := imx-wm8962.o snd-soc-imx-spdif-objs := imx-spdif.o @@ -61,6 +62,7 @@ obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o +obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c new file mode 100644 index 000000000000..653e66d150c8 --- /dev/null +++ b/sound/soc/fsl/imx-es8328.c @@ -0,0 +1,232 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imx-audmux.h" + +#define DAI_NAME_SIZE 32 +#define MUX_PORT_MAX 7 + +struct imx_es8328_data { + struct device *dev; + struct snd_soc_dai_link dai; + struct snd_soc_card card; + char codec_dai_name[DAI_NAME_SIZE]; + char platform_name[DAI_NAME_SIZE]; + int jack_gpio; +}; + +static struct snd_soc_jack_gpio headset_jack_gpios[] = { + { + .gpio = -1, + .name = "headset-gpio", + .report = SND_JACK_HEADSET, + .invert = 0, + .debounce_time = 200, + }, +}; + +static struct snd_soc_jack headset_jack; + +static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct imx_es8328_data *data = container_of(rtd->card, + struct imx_es8328_data, card); + int ret = 0; + + /* Headphone jack detection */ + if (gpio_is_valid(data->jack_gpio)) { + ret = snd_soc_jack_new(rtd->codec, "Headphone", + SND_JACK_HEADPHONE | SND_JACK_BTN_0, + &headset_jack); + if (ret) + return ret; + + headset_jack_gpios[0].gpio = data->jack_gpio; + ret = snd_soc_jack_add_gpios(&headset_jack, + ARRAY_SIZE(headset_jack_gpios), + headset_jack_gpios); + } + + return ret; +} + +static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0), +}; + +static int imx_es8328_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *ssi_np, *codec_np; + struct platform_device *ssi_pdev; + struct imx_es8328_data *data; + u32 int_port, ext_port; + int ret; + struct device *dev = &pdev->dev; + + ret = of_property_read_u32(np, "mux-int-port", &int_port); + if (ret) { + dev_err(dev, "mux-int-port missing or invalid\n"); + goto fail; + } + if (int_port > MUX_PORT_MAX || int_port == 0) { + dev_err(dev, "mux-int-port: hardware only has %d mux ports\n", + MUX_PORT_MAX); + goto fail; + } + + ret = of_property_read_u32(np, "mux-ext-port", &ext_port); + if (ret) { + dev_err(dev, "mux-ext-port missing or invalid\n"); + goto fail; + } + if (ext_port > MUX_PORT_MAX || ext_port == 0) { + dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n", + MUX_PORT_MAX); + goto fail; + } + + /* + * The port numbering in the hardware manual starts at 1, while + * the audmux API expects it starts at 0. + */ + int_port--; + ext_port--; + ret = imx_audmux_v2_configure_port(int_port, + IMX_AUDMUX_V2_PTCR_SYN | + IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR, + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); + if (ret) { + dev_err(dev, "audmux internal port setup failed\n"); + return ret; + } + ret = imx_audmux_v2_configure_port(ext_port, + IMX_AUDMUX_V2_PTCR_SYN, + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); + if (ret) { + dev_err(dev, "audmux external port setup failed\n"); + return ret; + } + + ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0); + codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0); + if (!ssi_np || !codec_np) { + dev_err(dev, "phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + ssi_pdev = of_find_device_by_node(ssi_np); + if (!ssi_pdev) { + dev_err(dev, "failed to find SSI platform device\n"); + ret = -EINVAL; + goto fail; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto fail; + } + + data->dev = dev; + + data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0); + + data->dai.name = "hifi"; + data->dai.stream_name = "hifi"; + data->dai.codec_dai_name = "es8328-hifi-analog"; + data->dai.codec_of_node = codec_np; + data->dai.cpu_of_node = ssi_np; + data->dai.platform_of_node = ssi_np; + data->dai.init = &imx_es8328_dai_init; + data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; + + data->card.dev = dev; + data->card.dapm_widgets = imx_es8328_dapm_widgets; + data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets); + ret = snd_soc_of_parse_card_name(&data->card, "model"); + if (ret) { + dev_err(dev, "Unable to parse card name\n"); + goto fail; + } + ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); + if (ret) { + dev_err(dev, "Unable to parse routing: %d\n", ret); + goto fail; + } + data->card.num_links = 1; + data->card.owner = THIS_MODULE; + data->card.dai_link = &data->dai; + + ret = snd_soc_register_card(&data->card); + if (ret) { + dev_err(dev, "Unable to register: %d\n", ret); + goto fail; + } + + platform_set_drvdata(pdev, data); +fail: + of_node_put(ssi_np); + of_node_put(codec_np); + + return ret; +} + +static int imx_es8328_remove(struct platform_device *pdev) +{ + struct imx_es8328_data *data = platform_get_drvdata(pdev); + + snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios), + headset_jack_gpios); + + snd_soc_unregister_card(&data->card); + + return 0; +} + +static const struct of_device_id imx_es8328_dt_ids[] = { + { .compatible = "fsl,imx-audio-es8328", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids); + +static struct platform_driver imx_es8328_driver = { + .driver = { + .name = "imx-es8328", + .of_match_table = imx_es8328_dt_ids, + }, + .probe = imx_es8328_probe, + .remove = imx_es8328_remove, +}; +module_platform_driver(imx_es8328_driver); + +MODULE_AUTHOR("Sean Cross "); +MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:imx-audio-es8328"); -- GitLab From 855675f6e6a65688a7f4cf45b9b5a98cf6c6f5c3 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Mon, 4 Aug 2014 15:07:25 +0800 Subject: [PATCH 0355/5088] ASoC: fsl_sai: Set SYNC bit of TCR2 to Asynchronous Mode There is one design rule according to SAI's reference manual: If the transmitter bit clock and frame sync are to be used by both transmitter and receiver, the transmitter must be configured for asynchronous operation and the receiver for synchronous operation. And SYNC of TCR2 is a 2-width control bit: 00 Asynchronous mode. 01 Synchronous with receiver. 10 Synchronous with another SAI transmitter. 11 Synchronous with another SAI receiver. So the driver should have set SYNC bit of TCR2 to 0x0, and meanwhile set SYNC bit of RCR2 to 0x1 (Synchronous with transmitter). Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 4c9e71c2f52a..60fe7c77ba22 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -334,8 +334,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, - sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); -- GitLab From 8a36eaa2ff4a9452a78d799503b920b4e1a0ec31 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 12:03:05 +0200 Subject: [PATCH 0356/5088] ASoC: dmic: Add to SND_SOC_ALL_CODECS Improve build coverage of the dmic driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..e514e98e48c4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -56,6 +56,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_DA7213 if I2C select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C + select SND_SOC_DMIC select SND_SOC_BT_SCO select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC -- GitLab From 371e07ec837464375fe4d7ef3bd13e13cdfbb458 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 16:18:17 +0200 Subject: [PATCH 0357/5088] ASoC: edma-pcm: Include edma-pcm.h edma_pcm_platform_register() is declared in edma-pcm.h and defined in edma-pcm.c. To make sure that the function signature matches for both edma-pcm.c should include edma-pcm.h Fixes the following sparse warning: sound/soc/davinci/edma-pcm.c:48:5: warning: symbol 'edma_pcm_platform_register' was not declared. Should it be static? Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/davinci/edma-pcm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c index 605e643133db..59e588abe54b 100644 --- a/sound/soc/davinci/edma-pcm.c +++ b/sound/soc/davinci/edma-pcm.c @@ -25,6 +25,8 @@ #include #include +#include "edma-pcm.h" + static const struct snd_pcm_hardware edma_pcm_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | -- GitLab From d80a12f92466d0bc4fd244c9052a8a88518c868e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 16:18:18 +0200 Subject: [PATCH 0358/5088] ASoC: odrodix2_max98090: Make non exported symbols static odroidx2_drvdata and odroidu3_drvdata are not used outside this module so make them static (and also const while we are at it). Fixes the following warnings from sparse: sound/soc/samsung/odroidx2_max98090.c:69:26: warning: symbol 'odroidx2_drvdata' was not declared. Should it be static? sound/soc/samsung/odroidx2_max98090.c:74:26: warning: symbol 'odroidu3_drvdata' was not declared. Should it be static? Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/odroidx2_max98090.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c index 278edf9e2a87..3c8f60423e82 100644 --- a/sound/soc/samsung/odroidx2_max98090.c +++ b/sound/soc/samsung/odroidx2_max98090.c @@ -66,12 +66,12 @@ static struct snd_soc_card odroidx2 = { .late_probe = odroidx2_late_probe, }; -struct odroidx2_drv_data odroidx2_drvdata = { +static const struct odroidx2_drv_data odroidx2_drvdata = { .dapm_widgets = odroidx2_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(odroidx2_dapm_widgets), }; -struct odroidx2_drv_data odroidu3_drvdata = { +static const struct odroidx2_drv_data odroidu3_drvdata = { .dapm_widgets = odroidu3_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(odroidu3_dapm_widgets), }; -- GitLab From 6c7d1dfca999f58c65ed7b10c2f0945dd92db103 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 16:18:20 +0200 Subject: [PATCH 0359/5088] ASoC: sh: Fix dma direction type dmaengine_prep_slave_single() expects a enum dma_transfer_direction and not a enum dma_data_direction. Since the integer representations of both DMA_TO_DEVICE and DMA_MEM_TO_DEV aswell as DMA_FROM_DEVICE and DMA_DEV_TO_MEM have the same value the code worked fine even though it was using the wrong type. Fixes the following warnings from sparse: sound/soc/sh/fsi.c:1307:42: warning: mixing different enum types sound/soc/sh/fsi.c:1307:42: int enum dma_data_direction versus sound/soc/sh/fsi.c:1307:42: int enum dma_transfer_direction Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index c76344350e44..66fddec9543d 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1297,9 +1297,14 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) struct snd_pcm_substream *substream = io->substream; struct dma_async_tx_descriptor *desc; int is_play = fsi_stream_is_play(fsi, io); - enum dma_data_direction dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + enum dma_transfer_direction dir; int ret = -EIO; + if (is_play) + dir = DMA_MEM_TO_DEV; + else + dir = DMA_DEV_TO_MEM; + desc = dmaengine_prep_dma_cyclic(io->chan, substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), -- GitLab From e8a70c25b809367fc314743e1ba1dbf0159398a7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 16:18:21 +0200 Subject: [PATCH 0360/5088] ASoC: samsung idma: Add proper annotation for casting iomem pointers It is not always possible to interchange iomem pointers with normal pointers, which why we have annotations for iomem pointers and warn when casting them to a normal pointer or vice versa. In this case the casting is fine and unfortunately necessary so add the proper annotations to tell code checkers that it is intentional. This silences the following warnings from sparse: sound/soc/samsung/idma.c:354:20: warning: incorrect type in argument 1 (different address spaces) expected void volatile [noderef] *addr got unsigned char *area sound/soc/samsung/idma.c:372:22: warning: cast removes address space of expression Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/idma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c index db6cefa18017..0e8dd985fcb3 100644 --- a/sound/soc/samsung/idma.c +++ b/sound/soc/samsung/idma.c @@ -351,7 +351,7 @@ static void idma_free(struct snd_pcm *pcm) if (!buf->area) return; - iounmap(buf->area); + iounmap((void __iomem *)buf->area); buf->area = NULL; buf->addr = 0; @@ -369,7 +369,7 @@ static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream) buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS; buf->addr = idma.lp_tx_addr; buf->bytes = idma_hardware.buffer_bytes_max; - buf->area = (unsigned char *)ioremap(buf->addr, buf->bytes); + buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes); return 0; } -- GitLab From 6391fffb7b6099fae0e869229279d147c47f617a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 16:18:22 +0200 Subject: [PATCH 0361/5088] ASoC: ab8500-codec: Drop bank prefix from AB8500_GPIO_DIR4_REG register define The AB8500_GPIO_DIR4_REG register define has the bank for the register in the upper 8 bits and the register itself in the lower 8 bits. When passing it to abx500_{set,get}_register_interruptible() the upper bits get truncated which generates the following warning from sparse: sound/soc/codecs/ab8500-codec.c:1972:53: warning: cast truncates bits from constant value (1013 becomes 13) sound/soc/codecs/ab8500-codec.c:1980:53: warning: cast truncates bits from constant value (1013 becomes 13) The bank is passed separately to abx500_{set,get}_register_interruptible() so the code works fine as it is. Given that all users of AB8500_GPIO_DIR4_REG always truncate the upper 8 bits just remove them from the define. Also remove the unnecessary casts to u8. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 1fb4402bf72d..62cf231f34cb 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -56,8 +56,7 @@ #define GPIO31_DIR_OUTPUT 0x40 /* Macrocell register definitions */ -#define AB8500_CTRL3_REG 0x0200 -#define AB8500_GPIO_DIR4_REG 0x1013 +#define AB8500_GPIO_DIR4_REG 0x13 /* Bank AB8500_MISC */ /* Nr of FIR/IIR-coeff banks in ANC-block */ #define AB8500_NR_OF_ANC_COEFF_BANKS 2 @@ -1968,16 +1967,16 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec, dev_dbg(codec->dev, "%s: Enter.\n", __func__); /* Set DMic-clocks to outputs */ - status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC, - (u8)AB8500_GPIO_DIR4_REG, + status = abx500_get_register_interruptible(codec->dev, AB8500_MISC, + AB8500_GPIO_DIR4_REG, &value8); if (status < 0) return status; value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT | GPIO31_DIR_OUTPUT; status = abx500_set_register_interruptible(codec->dev, - (u8)AB8500_MISC, - (u8)AB8500_GPIO_DIR4_REG, + AB8500_MISC, + AB8500_GPIO_DIR4_REG, value); if (status < 0) return status; -- GitLab From 89323f8c504a8653c66fe4a314723b36b07e29e1 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 23 Jul 2014 17:40:30 +0300 Subject: [PATCH 0362/5088] irqchip: keystone: Add irq controller ip driver On Keystone SOCs, DSP cores can send interrupts to ARM host using the IRQ controller IP. It provides 28 IRQ signals to ARM. The IRQ handler running on HOST OS can identify DSP signal source by analyzing SRCCx bits in IPCARx registers. This is one of the component used by the IPC mechanism used on Keystone SOCs. Signed-off-by: Grygorii Strashko Link: https://lkml.kernel.org/r/1406126430-9978-1-git-send-email-grygorii.strashko@ti.com Signed-off-by: Jason Cooper --- .../interrupt-controller/ti,keystone-irq.txt | 36 +++ drivers/irqchip/Kconfig | 7 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-keystone.c | 232 ++++++++++++++++++ 4 files changed, 276 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt create mode 100644 drivers/irqchip/irq-keystone.c diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt new file mode 100644 index 000000000000..d9bb106bdd16 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt @@ -0,0 +1,36 @@ +Keystone 2 IRQ controller IP + +On Keystone SOCs, DSP cores can send interrupts to ARM +host using the IRQ controller IP. It provides 28 IRQ signals to ARM. +The IRQ handler running on HOST OS can identify DSP signal source by +analyzing SRCCx bits in IPCARx registers. This is one of the component +used by the IPC mechanism used on Keystone SOCs. + +Required Properties: +- compatible: should be "ti,keystone-irq" +- ti,syscon-dev : phandle and offset pair. The phandle to syscon used to + access device control registers and the offset inside + device control registers range. +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode interrupt + source should be 1. +- interrupts: interrupt reference to primary interrupt controller + +Please refer to interrupts.txt in this directory for details of the common +Interrupt Controllers bindings used by client devices. + +Example: + kirq0: keystone_irq0@026202a0 { + compatible = "ti,keystone-irq"; + ti,syscon-dev = <&devctrl 0x2a0>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + }; + + dsp0: dsp0 { + compatible = "linux,rproc-user"; + ... + interrupt-parent = <&kirq0>; + interrupts = <10 2>; + }; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index b8632bf9a7f3..c88896478e70 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -113,3 +113,10 @@ config IRQ_CROSSBAR The primary irqchip invokes the crossbar's callback which inturn allocates a free irq and configures the IP. Thus the peripheral interrupts are routed to one of the free irqchip interrupt lines. + +config KEYSTONE_IRQ + tristate "Keystone 2 IRQ controller IP" + depends on ARCH_KEYSTONE + help + Support for Texas Instruments Keystone 2 IRQ controller IP which + is part of the Keystone 2 IPC mechanism diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 73052ba9ca62..69fc7fc8d1bb 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -34,3 +34,4 @@ obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o +obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c new file mode 100644 index 000000000000..fea26bcfd4ea --- /dev/null +++ b/drivers/irqchip/irq-keystone.c @@ -0,0 +1,232 @@ +/* + * Texas Instruments Keystone IRQ controller IP driver + * + * Copyright (C) 2014 Texas Instruments, Inc. + * Author: Sajesh Kumar Saran + * Grygorii Strashko + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; 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 "irqchip.h" + + +/* The source ID bits start from 4 to 31 (total 28 bits)*/ +#define BIT_OFS 4 +#define KEYSTONE_N_IRQ (32 - BIT_OFS) + +struct keystone_irq_device { + struct device *dev; + struct irq_chip chip; + u32 mask; + u32 irq; + struct irq_domain *irqd; + struct regmap *devctrl_regs; + u32 devctrl_offset; +}; + +static inline u32 keystone_irq_readl(struct keystone_irq_device *kirq) +{ + int ret; + u32 val = 0; + + ret = regmap_read(kirq->devctrl_regs, kirq->devctrl_offset, &val); + if (ret < 0) + dev_dbg(kirq->dev, "irq read failed ret(%d)\n", ret); + return val; +} + +static inline void +keystone_irq_writel(struct keystone_irq_device *kirq, u32 value) +{ + int ret; + + ret = regmap_write(kirq->devctrl_regs, kirq->devctrl_offset, value); + if (ret < 0) + dev_dbg(kirq->dev, "irq write failed ret(%d)\n", ret); +} + +static void keystone_irq_setmask(struct irq_data *d) +{ + struct keystone_irq_device *kirq = irq_data_get_irq_chip_data(d); + + kirq->mask |= BIT(d->hwirq); + dev_dbg(kirq->dev, "mask %lu [%x]\n", d->hwirq, kirq->mask); +} + +static void keystone_irq_unmask(struct irq_data *d) +{ + struct keystone_irq_device *kirq = irq_data_get_irq_chip_data(d); + + kirq->mask &= ~BIT(d->hwirq); + dev_dbg(kirq->dev, "unmask %lu [%x]\n", d->hwirq, kirq->mask); +} + +static void keystone_irq_ack(struct irq_data *d) +{ + /* nothing to do here */ +} + +static void keystone_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc); + unsigned long pending; + int src, virq; + + dev_dbg(kirq->dev, "start irq %d\n", irq); + + chained_irq_enter(irq_desc_get_chip(desc), desc); + + pending = keystone_irq_readl(kirq); + keystone_irq_writel(kirq, pending); + + dev_dbg(kirq->dev, "pending 0x%lx, mask 0x%x\n", pending, kirq->mask); + + pending = (pending >> BIT_OFS) & ~kirq->mask; + + dev_dbg(kirq->dev, "pending after mask 0x%lx\n", pending); + + for (src = 0; src < KEYSTONE_N_IRQ; src++) { + if (BIT(src) & pending) { + virq = irq_find_mapping(kirq->irqd, src); + dev_dbg(kirq->dev, "dispatch bit %d, virq %d\n", + src, virq); + if (!virq) + dev_warn(kirq->dev, "sporious irq detected hwirq %d, virq %d\n", + src, virq); + generic_handle_irq(virq); + } + } + + chained_irq_exit(irq_desc_get_chip(desc), desc); + + dev_dbg(kirq->dev, "end irq %d\n", irq); +} + +static int keystone_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct keystone_irq_device *kirq = h->host_data; + + irq_set_chip_data(virq, kirq); + irq_set_chip_and_handler(virq, &kirq->chip, handle_level_irq); + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + return 0; +} + +static struct irq_domain_ops keystone_irq_ops = { + .map = keystone_irq_map, + .xlate = irq_domain_xlate_onecell, +}; + +static int keystone_irq_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct keystone_irq_device *kirq; + int ret; + + if (np == NULL) + return -EINVAL; + + kirq = devm_kzalloc(dev, sizeof(*kirq), GFP_KERNEL); + if (!kirq) + return -ENOMEM; + + kirq->devctrl_regs = + syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev"); + if (IS_ERR(kirq->devctrl_regs)) + return PTR_ERR(kirq->devctrl_regs); + + ret = of_property_read_u32_index(np, "ti,syscon-dev", 1, + &kirq->devctrl_offset); + if (ret) { + dev_err(dev, "couldn't read the devctrl_offset offset!\n"); + return ret; + } + + kirq->irq = platform_get_irq(pdev, 0); + if (kirq->irq < 0) { + dev_err(dev, "no irq resource %d\n", kirq->irq); + return kirq->irq; + } + + kirq->dev = dev; + kirq->mask = ~0x0; + kirq->chip.name = "keystone-irq"; + kirq->chip.irq_ack = keystone_irq_ack; + kirq->chip.irq_mask = keystone_irq_setmask; + kirq->chip.irq_unmask = keystone_irq_unmask; + + kirq->irqd = irq_domain_add_linear(np, KEYSTONE_N_IRQ, + &keystone_irq_ops, kirq); + if (!kirq->irqd) { + dev_err(dev, "IRQ domain registration failed\n"); + return -ENODEV; + } + + platform_set_drvdata(pdev, kirq); + + irq_set_chained_handler(kirq->irq, keystone_irq_handler); + irq_set_handler_data(kirq->irq, kirq); + + /* clear all source bits */ + keystone_irq_writel(kirq, ~0x0); + + dev_info(dev, "irqchip registered, nr_irqs %u\n", KEYSTONE_N_IRQ); + + return 0; +} + +static int keystone_irq_remove(struct platform_device *pdev) +{ + struct keystone_irq_device *kirq = platform_get_drvdata(pdev); + int hwirq; + + for (hwirq = 0; hwirq < KEYSTONE_N_IRQ; hwirq++) + irq_dispose_mapping(irq_find_mapping(kirq->irqd, hwirq)); + + irq_domain_remove(kirq->irqd); + return 0; +} + +static const struct of_device_id keystone_irq_dt_ids[] = { + { .compatible = "ti,keystone-irq", }, + {}, +}; +MODULE_DEVICE_TABLE(of, keystone_irq_dt_ids); + +static struct platform_driver keystone_irq_device_driver = { + .probe = keystone_irq_probe, + .remove = keystone_irq_remove, + .driver = { + .name = "keystone_irq", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(keystone_irq_dt_ids), + } +}; + +module_platform_driver(keystone_irq_device_driver); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_AUTHOR("Sajesh Kumar Saran"); +MODULE_AUTHOR("Grygorii Strashko"); +MODULE_DESCRIPTION("Keystone IRQ chip"); +MODULE_LICENSE("GPL v2"); -- GitLab From f530504a063cfa028971e4b26ea8e0c32908de25 Mon Sep 17 00:00:00 2001 From: chai wen Date: Mon, 11 Aug 2014 10:49:23 -0400 Subject: [PATCH 0363/5088] watchdog: Remove unnecessary header files Signed-off-by: chai wen Signed-off-by: Don Zickus Cc: pbonzini@redhat.com Link: http://lkml.kernel.org/r/1407768567-171794-2-git-send-email-dzickus@redhat.com Signed-off-by: Ingo Molnar --- kernel/watchdog.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index c3319bd1b040..4c2e11ce5425 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -15,11 +15,6 @@ #include #include #include -#include -#include -#include -#include -#include #include #include #include -- GitLab From df577149594cefacd62740e86de080c6336d699e Mon Sep 17 00:00:00 2001 From: Ulrich Obergfell Date: Mon, 11 Aug 2014 10:49:25 -0400 Subject: [PATCH 0364/5088] watchdog: Fix print-once on enable This patch avoids printing the message 'enabled on all CPUs, ...' multiple times. For example, the issue can occur in the following scenario: 1) watchdog_nmi_enable() fails to enable PMU counters and sets cpu0_err. 2) 'echo [0|1] > /proc/sys/kernel/nmi_watchdog' is executed to disable and re-enable the watchdog mechanism 'on the fly'. 3) If watchdog_nmi_enable() succeeds to enable PMU counters, each CPU will print the message because step1 left behind a non-zero cpu0_err. if (!IS_ERR(event)) { if (cpu == 0 || cpu0_err) pr_info("enabled on all CPUs, ...") The patch avoids this by clearing cpu0_err in watchdog_nmi_disable(). Signed-off-by: Ulrich Obergfell Signed-off-by: Andrew Jones Signed-off-by: Don Zickus Cc: pbonzini@redhat.com Link: http://lkml.kernel.org/r/1407768567-171794-4-git-send-email-dzickus@redhat.com [ Applied small cleanups. ] Signed-off-by: Ingo Molnar --- kernel/watchdog.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 4c2e11ce5425..df5494edf694 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -506,7 +506,10 @@ static void watchdog_nmi_disable(unsigned int cpu) /* should be in cleanup, but blocks oprofile */ perf_event_release_kernel(event); } - return; + if (cpu == 0) { + /* watchdog_nmi_enable() expects this to be zero initially. */ + cpu0_err = 0; + } } #else static int watchdog_nmi_enable(unsigned int cpu) { return 0; } -- GitLab From ba07975f0fe5bf95107d71d0df0405c16f5c3266 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 25 Jun 2014 18:05:30 -0700 Subject: [PATCH 0365/5088] gpu: ipu-v3: Add functions to set CSI/IC source muxes Adds two new functions, ipu_set_csi_src_mux() and ipu_set_ic_src_mux(), that select the inputs to the CSI and IC respectively. Both muxes are programmed in the IPU_CONF register. Signed-off-by: Steve Longerbeam Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-common.c | 51 +++++++++++++++++++++++++++++++++ include/video/imx-ipu-v3.h | 6 ++++ 2 files changed, 57 insertions(+) diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 5978e7aab8ed..cae543115856 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -382,6 +382,57 @@ static int ipu_memory_reset(struct ipu_soc *ipu) return 0; } +/* + * Set the source mux for the given CSI. Selects either parallel or + * MIPI CSI2 sources. + */ +void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2) +{ + unsigned long flags; + u32 val, mask; + + mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE : + IPU_CONF_CSI0_DATA_SOURCE; + + spin_lock_irqsave(&ipu->lock, flags); + + val = ipu_cm_read(ipu, IPU_CONF); + if (mipi_csi2) + val |= mask; + else + val &= ~mask; + ipu_cm_write(ipu, val, IPU_CONF); + + spin_unlock_irqrestore(&ipu->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux); + +/* + * Set the source mux for the IC. Selects either CSI[01] or the VDI. + */ +void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&ipu->lock, flags); + + val = ipu_cm_read(ipu, IPU_CONF); + if (vdi) { + val |= IPU_CONF_IC_INPUT; + } else { + val &= ~IPU_CONF_IC_INPUT; + if (csi_id == 1) + val |= IPU_CONF_CSI_SEL; + else + val &= ~IPU_CONF_CSI_SEL; + } + ipu_cm_write(ipu, val, IPU_CONF); + + spin_unlock_irqrestore(&ipu->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux); + struct ipu_devtype { const char *name; unsigned long cm_ofs; diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index ef64b66b18df..f80fe13b0d4d 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -92,6 +92,12 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, #define IPU_IRQ_VSYNC_PRE_0 (448 + 14) #define IPU_IRQ_VSYNC_PRE_1 (448 + 15) +/* + * IPU Common functions + */ +void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2); +void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi); + /* * IPU Image DMA Controller (idmac) functions */ -- GitLab From c2d670fd3b16304124162bef99313eaa289f2bc3 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 25 Jun 2014 18:05:31 -0700 Subject: [PATCH 0366/5088] gpu: ipu-v3: Rename and add IDMAC channels Rename the ENC/VF/PP rotation channel names, to be more consistent with the convention that *_MEM is write-to-memory channels and MEM_* is read-from-memory channels. Also add the channels who's source and destination is the IC. Signed-off-by: Steve Longerbeam Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-prv.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h index 0a7b2adaba39..1a5c55c05fe8 100644 --- a/drivers/gpu/ipu-v3/ipu-prv.h +++ b/drivers/gpu/ipu-v3/ipu-prv.h @@ -28,17 +28,25 @@ struct ipu_soc; #define IPUV3_CHANNEL_CSI1 1 #define IPUV3_CHANNEL_CSI2 2 #define IPUV3_CHANNEL_CSI3 3 +#define IPUV3_CHANNEL_VDI_MEM_IC_VF 5 +#define IPUV3_CHANNEL_MEM_IC_PP 11 +#define IPUV3_CHANNEL_MEM_IC_PRP_VF 12 +#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF 14 +#define IPUV3_CHANNEL_G_MEM_IC_PP 15 +#define IPUV3_CHANNEL_IC_PRP_ENC_MEM 20 +#define IPUV3_CHANNEL_IC_PRP_VF_MEM 21 +#define IPUV3_CHANNEL_IC_PP_MEM 22 #define IPUV3_CHANNEL_MEM_BG_SYNC 23 #define IPUV3_CHANNEL_MEM_FG_SYNC 27 #define IPUV3_CHANNEL_MEM_DC_SYNC 28 #define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31 #define IPUV3_CHANNEL_MEM_DC_ASYNC 41 -#define IPUV3_CHANNEL_ROT_ENC_MEM 45 -#define IPUV3_CHANNEL_ROT_VF_MEM 46 -#define IPUV3_CHANNEL_ROT_PP_MEM 47 -#define IPUV3_CHANNEL_ROT_ENC_MEM_OUT 48 -#define IPUV3_CHANNEL_ROT_VF_MEM_OUT 49 -#define IPUV3_CHANNEL_ROT_PP_MEM_OUT 50 +#define IPUV3_CHANNEL_MEM_ROT_ENC 45 +#define IPUV3_CHANNEL_MEM_ROT_VF 46 +#define IPUV3_CHANNEL_MEM_ROT_PP 47 +#define IPUV3_CHANNEL_ROT_ENC_MEM 48 +#define IPUV3_CHANNEL_ROT_VF_MEM 49 +#define IPUV3_CHANNEL_ROT_PP_MEM 50 #define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51 #define IPU_MCU_T_DEFAULT 8 -- GitLab From 5f37671e004eeca017b93f6b26f2425acbb8d411 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 18 Aug 2014 16:38:39 +0800 Subject: [PATCH 0367/5088] ASoC: fsl-asoc-card: Fix build warning for maybe-uninitialized When build fsl-asoc-card as module, there is following error: sound/soc/fsl/fsl-asoc-card.c: In function 'fsl_asoc_card_probe': >> sound/soc/fsl/fsl-asoc-card.c:547:13: warning: 'asrc_np' may be used uninitialized in this function [-Wmaybe-uninitialized] of_node_put(asrc_np); ^ vim +/asrc_np +547 sound/soc/fsl/fsl-asoc-card.c 531 if (width == 24) 532 priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE; 533 else 534 priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE; 535 } 536 537 /* Finish card registering */ 538 platform_set_drvdata(pdev, priv); 539 snd_soc_card_set_drvdata(&priv->card, priv); 540 541 ret = devm_snd_soc_register_card(&pdev->dev, &priv->card); 542 if (ret) 543 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); 544 545 fail: 546 of_node_put(codec_np); > 547 of_node_put(asrc_np); 548 of_node_put(cpu_np); 549 550 return ret; 551 } 552 553 static const struct of_device_id fsl_asoc_card_dt_ids[] = { 554 { .compatible = "fsl,imx-audio-cs42888", }, 555 { .compatible = "fsl,imx-audio-sgtl5000", }, Add 'asrc_fail' branch for error jump after asrc_np initialized. Reported-by: kbuild test robot Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index cf3f1f47f1e8..007c772f3cef 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -469,7 +469,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) ret = fsl_asoc_card_audmux_init(np, priv); if (ret) { dev_err(&pdev->dev, "failed to init audmux\n"); - goto fail; + goto asrc_fail; } } else if (strstr(cpu_np->name, "esai")) { priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; @@ -518,14 +518,14 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to get output rate\n"); ret = -EINVAL; - goto fail; + goto asrc_fail; } ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width); if (ret) { dev_err(&pdev->dev, "failed to get output rate\n"); ret = -EINVAL; - goto fail; + goto asrc_fail; } if (width == 24) @@ -542,9 +542,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); +asrc_fail: + of_node_put(asrc_np); fail: of_node_put(codec_np); - of_node_put(asrc_np); of_node_put(cpu_np); return ret; -- GitLab From 499898d66d88cc626a2e01b02c3b819536bdf169 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 18 Aug 2014 16:38:40 +0800 Subject: [PATCH 0368/5088] ASoC: fsl: fsl-asoc-card: Select SND_SOC_IMX_AUDMUX Building kernel with SND_SOC_IMX_AUDMUX=n leads to the following error: sound/built-in.o: In function `fsl_asoc_card_probe': >> fsl-asoc-card.c:(.text+0x1467b5): undefined reference to `imx_audmux_v2_configure_port' >> fsl-asoc-card.c:(.text+0x1467d0): undefined reference to `imx_audmux_v2_configure_port' >> fsl-asoc-card.c:(.text+0x1467ed): undefined reference to `imx_audmux_v2_configure_port' >> fsl-asoc-card.c:(.text+0x146807): undefined reference to `imx_audmux_v2_configure_port' Update Kconfig to select SND_SOC_IMX_AUDMUX when SND_SOC_FSL_ASOC_CARD=y. Reported-by: kbuild test robot Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index fa90340dc13a..4698c01af684 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -62,6 +62,7 @@ config SND_SOC_FSL_UTILS config SND_SOC_FSL_ASOC_CARD tristate "Generic ASoC Sound Card with ASRC support" depends on OF && I2C + select SND_SOC_IMX_AUDMUX select SND_SOC_IMX_PCM_DMA select SND_SOC_FSL_ESAI select SND_SOC_FSL_SAI -- GitLab From 8ea21348868f37f5b2e6ebbaf336d2a415b2b9ff Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 18 Aug 2014 15:00:15 +0800 Subject: [PATCH 0369/5088] ASoC: simple-card: Fix the compile warning. sound/soc/generic/simple-card.c: In function simple_card_dai_link_of: sound/soc/generic/simple-card.c:198:10: warning: passing argument 3 of asoc_simple_card_sub_parse_of from incompatible pointer type [enabled by default] &dai_link->cpu_dai_name); ^ sound/soc/generic/simple-card.c:112:1: note: expected const struct device_node ** but argument is of type struct device_node ** asoc_simple_card_sub_parse_of(struct device_node *np, ^ sound/soc/generic/simple-card.c:229:10: warning: passing argument 3 of asoc_simple_card_sub_parse_of from incompatible pointer type [enabled by default] &dai_link->codec_dai_name); ^ sound/soc/generic/simple-card.c:112:1: note: expected const struct device_node ** but argument is of type struct device_node ** asoc_simple_card_sub_parse_of(struct device_node *np, ^ Since the asoc_simple_card_sub_parse_of() is used in simple-card module only, and the third argument is just used to get the node ponters address, so there is no need it must to be 'const' type. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 159e517fa09a..21b0ea24bc1d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -111,7 +111,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) static int asoc_simple_card_sub_parse_of(struct device_node *np, struct asoc_simple_dai *dai, - const struct device_node **p_node, + struct device_node **p_node, const char **name) { struct device_node *node; -- GitLab From e9bd0224c130617d7d6037d3a405571c33b1e097 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Aug 2014 11:54:36 +0200 Subject: [PATCH 0370/5088] ALSA: hda - Remove obsoleted snd_hda_check_board_config() & co The helper functions snd_hda_check_board_config() and snd_hda_check_board_codec_sid_config() are no longer used since the transition to the generic parser and all quirks have been replaced with fixups. Let's kill these dead codes. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 115 -------------------------------------- sound/pci/hda/hda_local.h | 6 -- 2 files changed, 121 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ec6a7d0d1886..0aa2e1ed1dbc 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4816,121 +4816,6 @@ int snd_hda_build_pcms(struct hda_bus *bus) } EXPORT_SYMBOL_GPL(snd_hda_build_pcms); -/** - * snd_hda_check_board_config - compare the current codec with the config table - * @codec: the HDA codec - * @num_configs: number of config enums - * @models: array of model name strings - * @tbl: configuration table, terminated by null entries - * - * Compares the modelname or PCI subsystem id of the current codec with the - * given configuration table. If a matching entry is found, returns its - * config value (supposed to be 0 or positive). - * - * If no entries are matching, the function returns a negative value. - */ -int snd_hda_check_board_config(struct hda_codec *codec, - int num_configs, const char * const *models, - const struct snd_pci_quirk *tbl) -{ - if (codec->modelname && models) { - int i; - for (i = 0; i < num_configs; i++) { - if (models[i] && - !strcmp(codec->modelname, models[i])) { - codec_info(codec, "model '%s' is selected\n", - models[i]); - return i; - } - } - } - - if (!codec->bus->pci || !tbl) - return -1; - - tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl); - if (!tbl) - return -1; - if (tbl->value >= 0 && tbl->value < num_configs) { -#ifdef CONFIG_SND_DEBUG_VERBOSE - char tmp[10]; - const char *model = NULL; - if (models) - model = models[tbl->value]; - if (!model) { - sprintf(tmp, "#%d", tbl->value); - model = tmp; - } - codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n", - model, tbl->subvendor, tbl->subdevice, - (tbl->name ? tbl->name : "Unknown device")); -#endif - return tbl->value; - } - return -1; -} -EXPORT_SYMBOL_GPL(snd_hda_check_board_config); - -/** - * snd_hda_check_board_codec_sid_config - compare the current codec - subsystem ID with the - config table - - This is important for Gateway notebooks with SB450 HDA Audio - where the vendor ID of the PCI device is: - ATI Technologies Inc SB450 HDA Audio [1002:437b] - and the vendor/subvendor are found only at the codec. - - * @codec: the HDA codec - * @num_configs: number of config enums - * @models: array of model name strings - * @tbl: configuration table, terminated by null entries - * - * Compares the modelname or PCI subsystem id of the current codec with the - * given configuration table. If a matching entry is found, returns its - * config value (supposed to be 0 or positive). - * - * If no entries are matching, the function returns a negative value. - */ -int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, - int num_configs, const char * const *models, - const struct snd_pci_quirk *tbl) -{ - const struct snd_pci_quirk *q; - - /* Search for codec ID */ - for (q = tbl; q->subvendor; q++) { - unsigned int mask = 0xffff0000 | q->subdevice_mask; - unsigned int id = (q->subdevice | (q->subvendor << 16)) & mask; - if ((codec->subsystem_id & mask) == id) - break; - } - - if (!q->subvendor) - return -1; - - tbl = q; - - if (tbl->value >= 0 && tbl->value < num_configs) { -#ifdef CONFIG_SND_DEBUG_VERBOSE - char tmp[10]; - const char *model = NULL; - if (models) - model = models[tbl->value]; - if (!model) { - sprintf(tmp, "#%d", tbl->value); - model = tmp; - } - codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n", - model, tbl->subvendor, tbl->subdevice, - (tbl->name ? tbl->name : "Unknown device")); -#endif - return tbl->value; - } - return -1; -} -EXPORT_SYMBOL_GPL(snd_hda_check_board_codec_sid_config); - /** * snd_hda_add_new_ctls - create controls from the array * @codec: the HDA codec diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 364bb413e02a..8a018d4cbe98 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -371,12 +371,6 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen); /* * Misc */ -int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, - const char * const *modelnames, - const struct snd_pci_quirk *pci_list); -int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, - int num_configs, const char * const *models, - const struct snd_pci_quirk *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, const struct snd_kcontrol_new *knew); -- GitLab From e52faba0f3a5520fc766e24520c10cb79fee2fac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Aug 2014 11:57:05 +0200 Subject: [PATCH 0371/5088] ALSA: hda - Remove obsoleted EXPORT_SYMBOL_HDA() macro Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index bbc5a1392c75..9c8820f21f94 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -687,6 +687,4 @@ snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec, struct snd_dma_buffer *dmab) {} #endif -#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym) - #endif /* __SOUND_HDA_CODEC_H */ -- GitLab From f2a227cd3891266f1486a21aac86fa39b3abd093 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Aug 2014 13:35:22 +0200 Subject: [PATCH 0372/5088] ALSA: hda/realtek - Optimize alc888_coef_init() Just a refactoring using the existing helper functions. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 91 +++++++++++++++-------------------- 1 file changed, 40 insertions(+), 51 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d71270a3f73f..c9a7a2d237da 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -128,6 +128,43 @@ struct alc_spec { unsigned int coef0; }; +/* + * COEF access helper functions + */ + +static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx) +{ + unsigned int val; + + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx); + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0); + return val; +} + +#define alc_read_coef_idx(codec, coef_idx) \ + alc_read_coefex_idx(codec, 0x20, coef_idx) + +static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int coef_val) +{ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val); +} + +#define alc_write_coef_idx(codec, coef_idx, coef_val) \ + alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val) + +/* a special bypass for COEF 0; read the cached value at the second time */ +static unsigned int alc_get_coef0(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->coef0) + spec->coef0 = alc_read_coef_idx(codec, 0); + return spec->coef0; +} + /* * Append the given mixer and verb elements for the later use * The mixer array is referred in build_controls(), and init_verbs are @@ -231,19 +268,12 @@ static void alc880_unsol_event(struct hda_codec *codec, unsigned int res) /* additional initialization for ALC888 variants */ static void alc888_coef_init(struct hda_codec *codec) { - unsigned int tmp; - - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0); - tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); - if ((tmp & 0xf0) == 0x20) + if (alc_get_coef0(codec) == 0x20) /* alc888S-VC */ - snd_hda_codec_read(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x830); + alc_write_coef_idx(codec, 7, 0x830); else /* alc888-VB */ - snd_hda_codec_read(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x3030); + alc_write_coef_idx(codec, 7, 0x3030); } /* additional initialization for ALC889 variants */ @@ -586,47 +616,6 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) } } -/* - * COEF access helper functions - */ - -static int alc_read_coefex_idx(struct hda_codec *codec, - hda_nid_t nid, - unsigned int coef_idx) -{ - unsigned int val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, - coef_idx); - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PROC_COEF, 0); - return val; -} - -#define alc_read_coef_idx(codec, coef_idx) \ - alc_read_coefex_idx(codec, 0x20, coef_idx) - -static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, - unsigned int coef_idx, - unsigned int coef_val) -{ - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, - coef_idx); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, - coef_val); -} - -#define alc_write_coef_idx(codec, coef_idx, coef_val) \ - alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val) - -/* a special bypass for COEF 0; read the cached value at the second time */ -static unsigned int alc_get_coef0(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (!spec->coef0) - spec->coef0 = alc_read_coef_idx(codec, 0); - return spec->coef0; -} - /* */ -- GitLab From 1687ccc8b2229d05c579924086e9b42ada9db888 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Aug 2014 13:49:35 +0200 Subject: [PATCH 0373/5088] ALSA: hda/realtek - Use alc_write_coef_idx() in alc269_quanta_automake() Just a refactoring. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c9a7a2d237da..75614e53e60c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3355,15 +3355,8 @@ static void alc269_quanta_automute(struct hda_codec *codec) { snd_hda_gen_update_outputs(codec); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x680); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x480); + alc_write_coef_idx(codec, 0x0c, 0x680); + alc_write_coef_idx(codec, 0x0c, 0x480); } static void alc269_fixup_quanta_mute(struct hda_codec *codec, -- GitLab From 98b248839474293481905562ae38dc2d6558ef20 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Aug 2014 13:47:50 +0200 Subject: [PATCH 0374/5088] ALSA: hda/realtek - Add alc_update_coef*_idx() helper ... and rewrite a few open codes with them. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 277 ++++++++++------------------------ 1 file changed, 82 insertions(+), 195 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 75614e53e60c..fe041fa4f2c3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -155,6 +155,20 @@ static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, #define alc_write_coef_idx(codec, coef_idx, coef_val) \ alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val) +static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int mask, + unsigned int bits_set) +{ + unsigned int val = alc_read_coefex_idx(codec, nid, coef_idx); + + if (val != -1) + alc_write_coefex_idx(codec, nid, coef_idx, + (val & ~mask) | bits_set); +} + +#define alc_update_coef_idx(codec, coef_idx, mask, bits_set) \ + alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set) + /* a special bypass for COEF 0; read the cached value at the second time */ static unsigned int alc_get_coef0(struct hda_codec *codec) { @@ -210,20 +224,10 @@ static const struct hda_verb alc_gpio3_init_verbs[] = { static void alc_fix_pll(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int val; - if (!spec->pll_nid) - return; - snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, - spec->pll_coef_idx); - val = snd_hda_codec_read(codec, spec->pll_nid, 0, - AC_VERB_GET_PROC_COEF, 0); - if (val == -1) - return; - snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, - spec->pll_coef_idx); - snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF, - val & ~(1 << spec->pll_coef_bit)); + if (spec->pll_nid) + alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx, + 1 << spec->pll_coef_bit, 0); } static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, @@ -279,12 +283,7 @@ static void alc888_coef_init(struct hda_codec *codec) /* additional initialization for ALC889 variants */ static void alc889_coef_init(struct hda_codec *codec) { - unsigned int tmp; - - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010); + alc_update_coef_idx(codec, 7, 0, 0x2010); } /* turn on/off EAPD control (only if available) */ @@ -325,8 +324,6 @@ static void alc_eapd_shutup(struct hda_codec *codec) /* generic EAPD initialization */ static void alc_auto_init_amp(struct hda_codec *codec, int type) { - unsigned int tmp; - alc_auto_setup_eapd(codec, true); switch (type) { case ALC_INIT_GPIO1: @@ -341,15 +338,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) case ALC_INIT_DEFAULT: switch (codec->vendor_id) { case 0x10ec0260: - snd_hda_codec_write(codec, 0x1a, 0, - AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x1a, 0, - AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x1a, 0, - AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x1a, 0, - AC_VERB_SET_PROC_COEF, - tmp | 0x2010); + alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010); break; case 0x10ec0262: case 0x10ec0880: @@ -366,15 +355,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) #if 0 /* XXX: This may cause the silent output on speaker on some machines */ case 0x10ec0267: case 0x10ec0268: - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x20, 0, - AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, - tmp | 0x3000); + alc_update_coef_idx(codec, 7, 0, 0x3000); break; #endif /* XXX */ } @@ -2504,13 +2485,7 @@ static int patch_alc262(struct hda_codec *codec) /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is * under-run */ - { - int tmp; - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); - } + alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80); #endif alc_fix_pll_init(codec, 0x20, 0x0a, 10); @@ -2796,14 +2771,7 @@ static void alc286_shutup(struct hda_codec *codec) static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up) { - int val = alc_read_coef_idx(codec, 0x04); - if (val == -1) - return; - if (power_up) - val |= 1 << 11; - else - val &= ~(1 << 11); - alc_write_coef_idx(codec, 0x04, val); + alc_update_coef_idx(codec, 0x04, 1 << 11, power_up ? (1 << 11) : 0); } static void alc269_shutup(struct hda_codec *codec) @@ -2821,8 +2789,6 @@ static void alc269_shutup(struct hda_codec *codec) static void alc282_restore_default_value(struct hda_codec *codec) { - int val; - /* Power Down Control */ alc_write_coef_idx(codec, 0x03, 0x0002); /* FIFO and filter clock */ @@ -2830,11 +2796,9 @@ static void alc282_restore_default_value(struct hda_codec *codec) /* DMIC control */ alc_write_coef_idx(codec, 0x07, 0x0200); /* Analog clock */ - val = alc_read_coef_idx(codec, 0x06); - alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0); + alc_update_coef_idx(codec, 0x06, 0x00f0, 0); /* JD */ - val = alc_read_coef_idx(codec, 0x08); - alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c); + alc_update_coef_idx(codec, 0x08, 0xfffc, 0x0c2c); /* JD offset1 */ alc_write_coef_idx(codec, 0x0a, 0xcccc); /* JD offset2 */ @@ -2842,27 +2806,21 @@ static void alc282_restore_default_value(struct hda_codec *codec) /* LDO1/2/3, DAC/ADC */ alc_write_coef_idx(codec, 0x0e, 0x6e00); /* JD */ - val = alc_read_coef_idx(codec, 0x0f); - alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000); + alc_update_coef_idx(codec, 0x0f, 0xf800, 0x1000); /* Capless */ - val = alc_read_coef_idx(codec, 0x10); - alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00); + alc_update_coef_idx(codec, 0x10, 0xfc00, 0x0c00); /* Class D test 4 */ alc_write_coef_idx(codec, 0x6f, 0x0); /* IO power down directly */ - val = alc_read_coef_idx(codec, 0x0c); - alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0); + alc_update_coef_idx(codec, 0x0c, 0xfe00, 0); /* ANC */ alc_write_coef_idx(codec, 0x34, 0xa0c0); /* AGC MUX */ - val = alc_read_coef_idx(codec, 0x16); - alc_write_coef_idx(codec, 0x16, (val & ~0x0008) | 0x0); + alc_update_coef_idx(codec, 0x16, 0x0008, 0); /* DAC simple content protection */ - val = alc_read_coef_idx(codec, 0x1d); - alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0); + alc_update_coef_idx(codec, 0x1d, 0x00e0, 0); /* ADC simple content protection */ - val = alc_read_coef_idx(codec, 0x1f); - alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0); + alc_update_coef_idx(codec, 0x1f, 0x00e0, 0); /* DAC ADC Zero Detection */ alc_write_coef_idx(codec, 0x21, 0x8804); /* PLL */ @@ -2876,20 +2834,17 @@ static void alc282_restore_default_value(struct hda_codec *codec) /* capless control 5 */ alc_write_coef_idx(codec, 0x6b, 0x0); /* class D test 2 */ - val = alc_read_coef_idx(codec, 0x6d); - alc_write_coef_idx(codec, 0x6d, (val & ~0x0fff) | 0x0900); + alc_update_coef_idx(codec, 0x6d, 0x0fff, 0x0900); /* class D test 3 */ alc_write_coef_idx(codec, 0x6e, 0x110a); /* class D test 5 */ - val = alc_read_coef_idx(codec, 0x70); - alc_write_coef_idx(codec, 0x70, (val & ~0x00f8) | 0x00d8); + alc_update_coef_idx(codec, 0x70, 0x00f8, 0x00d8); /* class D test 6 */ alc_write_coef_idx(codec, 0x71, 0x0014); /* classD OCP */ alc_write_coef_idx(codec, 0x72, 0xc2ba); /* classD pure DC test */ - val = alc_read_coef_idx(codec, 0x77); - alc_write_coef_idx(codec, 0x77, (val & ~0x0f80) | 0x0); + alc_update_coef_idx(codec, 0x77, 0x0f80, 0); /* Class D amp control */ alc_write_coef_idx(codec, 0x6c, 0xfc06); } @@ -2969,8 +2924,6 @@ static void alc282_shutup(struct hda_codec *codec) static void alc283_restore_default_value(struct hda_codec *codec) { - int val; - /* Power Down Control */ alc_write_coef_idx(codec, 0x03, 0x0002); /* FIFO and filter clock */ @@ -2978,11 +2931,9 @@ static void alc283_restore_default_value(struct hda_codec *codec) /* DMIC control */ alc_write_coef_idx(codec, 0x07, 0x0200); /* Analog clock */ - val = alc_read_coef_idx(codec, 0x06); - alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0); + alc_update_coef_idx(codec, 0x06, 0x00f0, 0); /* JD */ - val = alc_read_coef_idx(codec, 0x08); - alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c); + alc_update_coef_idx(codec, 0x08, 0xfffc, 0x0c2c); /* JD offset1 */ alc_write_coef_idx(codec, 0x0a, 0xcccc); /* JD offset2 */ @@ -2990,27 +2941,21 @@ static void alc283_restore_default_value(struct hda_codec *codec) /* LDO1/2/3, DAC/ADC */ alc_write_coef_idx(codec, 0x0e, 0x6fc0); /* JD */ - val = alc_read_coef_idx(codec, 0x0f); - alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000); + alc_update_coef_idx(codec, 0x0f, 0xf800, 0x1000); /* Capless */ - val = alc_read_coef_idx(codec, 0x10); - alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00); + alc_update_coef_idx(codec, 0x10, 0xfc00, 0x0c00); /* Class D test 4 */ alc_write_coef_idx(codec, 0x3a, 0x0); /* IO power down directly */ - val = alc_read_coef_idx(codec, 0x0c); - alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0); + alc_update_coef_idx(codec, 0x0c, 0xfe00, 0x0); /* ANC */ alc_write_coef_idx(codec, 0x22, 0xa0c0); /* AGC MUX */ - val = alc_read_coefex_idx(codec, 0x53, 0x01); - alc_write_coefex_idx(codec, 0x53, 0x01, (val & ~0x000f) | 0x0008); + alc_update_coefex_idx(codec, 0x53, 0x01, 0x000f, 0x0008); /* DAC simple content protection */ - val = alc_read_coef_idx(codec, 0x1d); - alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0); + alc_update_coef_idx(codec, 0x1d, 0x00e0, 0x0); /* ADC simple content protection */ - val = alc_read_coef_idx(codec, 0x1f); - alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0); + alc_update_coef_idx(codec, 0x1f, 0x00e0, 0x0); /* DAC ADC Zero Detection */ alc_write_coef_idx(codec, 0x21, 0x8804); /* PLL */ @@ -3024,28 +2969,23 @@ static void alc283_restore_default_value(struct hda_codec *codec) /* capless control 5 */ alc_write_coef_idx(codec, 0x36, 0x0); /* class D test 2 */ - val = alc_read_coef_idx(codec, 0x38); - alc_write_coef_idx(codec, 0x38, (val & ~0x0fff) | 0x0900); + alc_update_coef_idx(codec, 0x38, 0x0fff, 0x0900); /* class D test 3 */ alc_write_coef_idx(codec, 0x39, 0x110a); /* class D test 5 */ - val = alc_read_coef_idx(codec, 0x3b); - alc_write_coef_idx(codec, 0x3b, (val & ~0x00f8) | 0x00d8); + alc_update_coef_idx(codec, 0x3b, 0x00f8, 0x00d8); /* class D test 6 */ alc_write_coef_idx(codec, 0x3c, 0x0014); /* classD OCP */ alc_write_coef_idx(codec, 0x3d, 0xc2ba); /* classD pure DC test */ - val = alc_read_coef_idx(codec, 0x42); - alc_write_coef_idx(codec, 0x42, (val & ~0x0f80) | 0x0); + alc_update_coef_idx(codec, 0x42, 0x0f80, 0x0); /* test mode */ alc_write_coef_idx(codec, 0x49, 0x0); /* Class D DC enable */ - val = alc_read_coef_idx(codec, 0x40); - alc_write_coef_idx(codec, 0x40, (val & ~0xf800) | 0x9800); + alc_update_coef_idx(codec, 0x40, 0xf800, 0x9800); /* DC offset */ - val = alc_read_coef_idx(codec, 0x42); - alc_write_coef_idx(codec, 0x42, (val & ~0xf000) | 0x2000); + alc_update_coef_idx(codec, 0x42, 0xf000, 0x2000); /* Class D amp control */ alc_write_coef_idx(codec, 0x37, 0xfc06); } @@ -3055,7 +2995,6 @@ static void alc283_init(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; bool hp_pin_sense; - int val; if (!spec->gen.autocfg.hp_outs) { if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT) @@ -3085,8 +3024,7 @@ static void alc283_init(struct hda_codec *codec) msleep(85); /* Index 0x46 Combo jack auto switch control 2 */ /* 3k pull low control for Headset jack. */ - val = alc_read_coef_idx(codec, 0x46); - alc_write_coef_idx(codec, 0x46, val & ~(3 << 12)); + alc_update_coef_idx(codec, 0x46, 3 << 12, 0); /* Headphone capless set to normal mode */ alc_write_coef_idx(codec, 0x43, 0x9614); } @@ -3096,7 +3034,6 @@ static void alc283_shutup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; bool hp_pin_sense; - int val; if (!spec->gen.autocfg.hp_outs) { if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT) @@ -3121,8 +3058,7 @@ static void alc283_shutup(struct hda_codec *codec) snd_hda_codec_write(codec, hp_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - val = alc_read_coef_idx(codec, 0x46); - alc_write_coef_idx(codec, 0x46, val | (3 << 12)); + alc_update_coef_idx(codec, 0x46, 0, 3 << 12); if (hp_pin_sense) msleep(100); @@ -3285,12 +3221,8 @@ static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec, static void alc269_fixup_hweq(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - int coef; - - if (action != HDA_FIXUP_ACT_INIT) - return; - coef = alc_read_coef_idx(codec, 0x1e); - alc_write_coef_idx(codec, 0x1e, coef | 0x80); + if (action == HDA_FIXUP_ACT_INIT) + alc_update_coef_idx(codec, 0x1e, 0, 0x80); } static void alc269_fixup_headset_mic(struct hda_codec *codec, @@ -3338,17 +3270,13 @@ static void alc269_fixup_pcm_44k(struct hda_codec *codec, static void alc269_fixup_stereo_dmic(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - int coef; - - if (action != HDA_FIXUP_ACT_INIT) - return; /* The digital-mic unit sends PDM (differential signal) instead of * the standard PCM, thus you can't record a valid mono stream as is. * Below is a workaround specific to ALC269 to control the dmic * signal source as mono. */ - coef = alc_read_coef_idx(codec, 0x07); - alc_write_coef_idx(codec, 0x07, coef | 0x80); + if (action == HDA_FIXUP_ACT_INIT) + alc_update_coef_idx(codec, 0x07, 0, 0x80); } static void alc269_quanta_automute(struct hda_codec *codec) @@ -3602,8 +3530,6 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, static void alc_headset_mode_unplugged(struct hda_codec *codec) { - int val; - switch (codec->vendor_id) { case 0x10ec0255: /* LDO and MISC control */ @@ -3611,8 +3537,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) /* UAJ function set to menual mode */ alc_write_coef_idx(codec, 0x45, 0xd089); /* Direct Drive HP Amp control(Set to verb control)*/ - val = alc_read_coefex_idx(codec, 0x57, 0x05); - alc_write_coefex_idx(codec, 0x57, 0x05, val & ~(1<<14)); + alc_update_coefex_idx(codec, 0x57, 0x05, 1<<14, 0); /* Set MIC2 Vref gate with HP */ alc_write_coef_idx(codec, 0x06, 0x6104); /* Direct Drive HP Amp control */ @@ -3622,8 +3547,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) case 0x10ec0283: alc_write_coef_idx(codec, 0x1b, 0x0c0b); alc_write_coef_idx(codec, 0x45, 0xc429); - val = alc_read_coef_idx(codec, 0x35); - alc_write_coef_idx(codec, 0x35, val & 0xbfff); + alc_update_coef_idx(codec, 0x35, 0x4000, 0); alc_write_coef_idx(codec, 0x06, 0x2104); alc_write_coef_idx(codec, 0x1a, 0x0001); alc_write_coef_idx(codec, 0x26, 0x0004); @@ -3637,22 +3561,17 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) break; case 0x10ec0293: /* SET Line1 JD to 0 */ - val = alc_read_coef_idx(codec, 0x10); - alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 6<<8); + alc_update_coef_idx(codec, 0x10, 7<<8, 6<<8); /* SET charge pump by verb */ - val = alc_read_coefex_idx(codec, 0x57, 0x05); - alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | 0x0); + alc_update_coefex_idx(codec, 0x57, 0x05, 1<<15|1<<13, 0x0); /* SET EN_OSW to 1 */ - val = alc_read_coefex_idx(codec, 0x57, 0x03); - alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | (1<<10) ); + alc_update_coefex_idx(codec, 0x57, 0x03, 1<<10, 1<<10); /* Combo JD gating with LINE1-VREFO */ - val = alc_read_coef_idx(codec, 0x1a); - alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | (1<<3)); + alc_update_coef_idx(codec, 0x1a, 1<<3, 1<<3); /* Set to TRS type */ alc_write_coef_idx(codec, 0x45, 0xc429); /* Combo Jack auto detect */ - val = alc_read_coef_idx(codec, 0x4a); - alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e); + alc_update_coef_idx(codec, 0x4a, 0x000f, 0x000e); break; case 0x10ec0668: alc_write_coef_idx(codec, 0x15, 0x0d40); @@ -3666,8 +3585,6 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, hda_nid_t mic_pin) { - int val; - switch (codec->vendor_id) { case 0x10ec0255: alc_write_coef_idx(codec, 0x45, 0xc489); @@ -3681,8 +3598,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, case 0x10ec0283: alc_write_coef_idx(codec, 0x45, 0xc429); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - val = alc_read_coef_idx(codec, 0x35); - alc_write_coef_idx(codec, 0x35, val | 1<<14); + alc_update_coef_idx(codec, 0x35, 0, 1<<14); alc_write_coef_idx(codec, 0x06, 0x2100); alc_write_coef_idx(codec, 0x1a, 0x0021); alc_write_coef_idx(codec, 0x26, 0x008c); @@ -3698,14 +3614,11 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, alc_write_coef_idx(codec, 0x45, 0xc429); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); /* SET charge pump by verb */ - val = alc_read_coefex_idx(codec, 0x57, 0x05); - alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | (1<<15|1<<13)); + alc_update_coefex_idx(codec, 0x57, 0x05, 0, 1<<15|1<<13); /* SET EN_OSW to 0 */ - val = alc_read_coefex_idx(codec, 0x57, 0x03); - alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | 0x0); + alc_update_coefex_idx(codec, 0x57, 0x03, 1<<10, 0); /* Combo JD gating without LINE1-VREFO */ - val = alc_read_coef_idx(codec, 0x1a); - alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0); + alc_update_coef_idx(codec, 0x1a, 1<<3, 0); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; case 0x10ec0668: @@ -3713,8 +3626,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); alc_write_coef_idx(codec, 0xb7, 0x802b); alc_write_coef_idx(codec, 0xb5, 0x1040); - val = alc_read_coef_idx(codec, 0xc3); - alc_write_coef_idx(codec, 0xc3, val | 1<<12); + alc_update_coef_idx(codec, 0xc3, 0, 1<<12); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; } @@ -3723,8 +3635,6 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, static void alc_headset_mode_default(struct hda_codec *codec) { - int val; - switch (codec->vendor_id) { case 0x10ec0255: alc_write_coef_idx(codec, 0x45, 0xc089); @@ -3745,13 +3655,11 @@ static void alc_headset_mode_default(struct hda_codec *codec) break; case 0x10ec0293: /* Combo Jack auto detect */ - val = alc_read_coef_idx(codec, 0x4a); - alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e); + alc_update_coef_idx(codec, 0x4a, 0x000f, 0x000e); /* Set to TRS type */ alc_write_coef_idx(codec, 0x45, 0xC429); /* Combo JD gating without LINE1-VREFO */ - val = alc_read_coef_idx(codec, 0x1a); - alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0); + alc_update_coef_idx(codec, 0x1a, 1<<3, 0); break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0041); @@ -3765,8 +3673,6 @@ static void alc_headset_mode_default(struct hda_codec *codec) /* Iphone type */ static void alc_headset_mode_ctia(struct hda_codec *codec) { - int val; - switch (codec->vendor_id) { case 0x10ec0255: /* Set to CTIA type */ @@ -3789,8 +3695,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) /* Set to ctia type */ alc_write_coef_idx(codec, 0x45, 0xd429); /* SET Line1 JD to 1 */ - val = alc_read_coef_idx(codec, 0x10); - alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8); + alc_update_coef_idx(codec, 0x10, 7<<8, 7<<8); break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); @@ -3804,8 +3709,6 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) /* Nokia type */ static void alc_headset_mode_omtp(struct hda_codec *codec) { - int val; - switch (codec->vendor_id) { case 0x10ec0255: /* Set to OMTP Type */ @@ -3828,8 +3731,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) /* Set to omtp type */ alc_write_coef_idx(codec, 0x45, 0xe429); /* SET Line1 JD to 1 */ - val = alc_read_coef_idx(codec, 0x10); - alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8); + alc_update_coef_idx(codec, 0x10, 7<<8, 7<<8); break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); @@ -3871,8 +3773,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) break; case 0x10ec0293: /* Combo Jack auto detect */ - val = alc_read_coef_idx(codec, 0x4a); - alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x0008); + alc_update_coef_idx(codec, 0x4a, 0x000f, 0x0008); /* Set to ctia type */ alc_write_coef_idx(codec, 0x45, 0xD429); msleep(300); @@ -4118,10 +4019,8 @@ static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, const struct hda_fixup *fix, int action) { if (action == HDA_FIXUP_ACT_PRE_PROBE) { - int val; alc_write_coef_idx(codec, 0xc4, 0x8000); - val = alc_read_coef_idx(codec, 0xc2); - alc_write_coef_idx(codec, 0xc2, val & 0xfe); + alc_update_coef_idx(codec, 0xc2, ~0xfe, 0); snd_hda_set_pin_ctl_cache(codec, 0x18, 0); } alc_fixup_headset_mode(codec, fix, action); @@ -4217,7 +4116,6 @@ static void alc283_fixup_chromebook(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - int val; switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: @@ -4228,11 +4126,9 @@ static void alc283_fixup_chromebook(struct hda_codec *codec, case HDA_FIXUP_ACT_INIT: /* MIC2-VREF control */ /* Set to manual mode */ - val = alc_read_coef_idx(codec, 0x06); - alc_write_coef_idx(codec, 0x06, val & ~0x000c); + alc_update_coef_idx(codec, 0x06, 0x000c, 0); /* Enable Line1 input control by verb */ - val = alc_read_coef_idx(codec, 0x1a); - alc_write_coef_idx(codec, 0x1a, val | (1 << 4)); + alc_update_coef_idx(codec, 0x1a, 0, 1 << 4); break; } } @@ -4241,7 +4137,6 @@ static void alc283_fixup_sense_combo_jack(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - int val; switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: @@ -4250,8 +4145,7 @@ static void alc283_fixup_sense_combo_jack(struct hda_codec *codec, case HDA_FIXUP_ACT_INIT: /* MIC2-VREF control */ /* Set to manual mode */ - val = alc_read_coef_idx(codec, 0x06); - alc_write_coef_idx(codec, 0x06, val & ~0x000c); + alc_update_coef_idx(codec, 0x06, 0x000c, 0); break; } } @@ -5304,10 +5198,8 @@ static void alc269_fill_coef(struct hda_codec *codec) } if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { - val = alc_read_coef_idx(codec, 0x04); /* Power up output pin */ - if (val != -1) - alc_write_coef_idx(codec, 0x04, val | (1<<11)); + alc_update_coef_idx(codec, 0x04, 0, 1<<11); } if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { @@ -5323,13 +5215,11 @@ static void alc269_fill_coef(struct hda_codec *codec) } } - val = alc_read_coef_idx(codec, 0xd); /* Class D */ - if (val != -1) - alc_write_coef_idx(codec, 0xd, val | (1<<14)); + /* Class D */ + alc_update_coef_idx(codec, 0xd, 0, 1<<14); - val = alc_read_coef_idx(codec, 0x4); /* HP */ - if (val != -1) - alc_write_coef_idx(codec, 0x4, val | (1<<11)); + /* HP */ + alc_update_coef_idx(codec, 0x4, 0, 1<<11); } /* @@ -6209,16 +6099,14 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { static void alc662_fill_coef(struct hda_codec *codec) { - int val, coef; + int coef; coef = alc_get_coef0(codec); switch (codec->vendor_id) { case 0x10ec0662: - if ((coef & 0x00f0) == 0x0030) { - val = alc_read_coef_idx(codec, 0x4); /* EAPD Ctrl */ - alc_write_coef_idx(codec, 0x4, val & ~(1<<10)); - } + if ((coef & 0x00f0) == 0x0030) + alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */ break; case 0x10ec0272: case 0x10ec0273: @@ -6227,8 +6115,7 @@ static void alc662_fill_coef(struct hda_codec *codec) case 0x10ec0670: case 0x10ec0671: case 0x10ec0672: - val = alc_read_coef_idx(codec, 0xd); /* EAPD Ctrl */ - alc_write_coef_idx(codec, 0xd, val | (1<<14)); + alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */ break; } } -- GitLab From 54db6c3949359ee35e9addb02506fca431721ef0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Aug 2014 15:11:19 +0200 Subject: [PATCH 0375/5088] ALSA: hda/realtek - Use tables for batch COEF writes/updtes There are many codes doing writes or updates COEF verbs sequentially in a batch. Rewrite such open codes with tables for optimization. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 559 +++++++++++++++++++--------------- 1 file changed, 314 insertions(+), 245 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index fe041fa4f2c3..e0fff47b5740 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -179,6 +179,32 @@ static unsigned int alc_get_coef0(struct hda_codec *codec) return spec->coef0; } +/* coef writes/updates batch */ +struct coef_fw { + unsigned char nid; + unsigned char idx; + unsigned short mask; + unsigned short val; +}; + +#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \ + { .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) } +#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val) +#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val) +#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val) + +static void alc_process_coef_fw(struct hda_codec *codec, + const struct coef_fw *fw) +{ + for (; fw->nid; fw++) { + if (fw->mask == (unsigned short)-1) + alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val); + else + alc_update_coefex_idx(codec, fw->nid, fw->idx, + fw->mask, fw->val); + } +} + /* * Append the given mixer and verb elements for the later use * The mixer array is referred in build_controls(), and init_verbs are @@ -2787,66 +2813,42 @@ static void alc269_shutup(struct hda_codec *codec) snd_hda_shutup_pins(codec); } +static struct coef_fw alc282_coefs[] = { + WRITE_COEF(0x03, 0x0002), /* Power Down Control */ + WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */ + WRITE_COEF(0x07, 0x0200), /* DMIC control */ + UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ + UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ + WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */ + WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */ + WRITE_COEF(0x0e, 0x6e00), /* LDO1/2/3, DAC/ADC */ + UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */ + UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */ + WRITE_COEF(0x6f, 0x0), /* Class D test 4 */ + UPDATE_COEF(0x0c, 0xfe00, 0), /* IO power down directly */ + WRITE_COEF(0x34, 0xa0c0), /* ANC */ + UPDATE_COEF(0x16, 0x0008, 0), /* AGC MUX */ + UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */ + UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */ + WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */ + WRITE_COEF(0x63, 0x2902), /* PLL */ + WRITE_COEF(0x68, 0xa080), /* capless control 2 */ + WRITE_COEF(0x69, 0x3400), /* capless control 3 */ + WRITE_COEF(0x6a, 0x2f3e), /* capless control 4 */ + WRITE_COEF(0x6b, 0x0), /* capless control 5 */ + UPDATE_COEF(0x6d, 0x0fff, 0x0900), /* class D test 2 */ + WRITE_COEF(0x6e, 0x110a), /* class D test 3 */ + UPDATE_COEF(0x70, 0x00f8, 0x00d8), /* class D test 5 */ + WRITE_COEF(0x71, 0x0014), /* class D test 6 */ + WRITE_COEF(0x72, 0xc2ba), /* classD OCP */ + UPDATE_COEF(0x77, 0x0f80, 0), /* classD pure DC test */ + WRITE_COEF(0x6c, 0xfc06), /* Class D amp control */ + {} +}; + static void alc282_restore_default_value(struct hda_codec *codec) { - /* Power Down Control */ - alc_write_coef_idx(codec, 0x03, 0x0002); - /* FIFO and filter clock */ - alc_write_coef_idx(codec, 0x05, 0x0700); - /* DMIC control */ - alc_write_coef_idx(codec, 0x07, 0x0200); - /* Analog clock */ - alc_update_coef_idx(codec, 0x06, 0x00f0, 0); - /* JD */ - alc_update_coef_idx(codec, 0x08, 0xfffc, 0x0c2c); - /* JD offset1 */ - alc_write_coef_idx(codec, 0x0a, 0xcccc); - /* JD offset2 */ - alc_write_coef_idx(codec, 0x0b, 0xcccc); - /* LDO1/2/3, DAC/ADC */ - alc_write_coef_idx(codec, 0x0e, 0x6e00); - /* JD */ - alc_update_coef_idx(codec, 0x0f, 0xf800, 0x1000); - /* Capless */ - alc_update_coef_idx(codec, 0x10, 0xfc00, 0x0c00); - /* Class D test 4 */ - alc_write_coef_idx(codec, 0x6f, 0x0); - /* IO power down directly */ - alc_update_coef_idx(codec, 0x0c, 0xfe00, 0); - /* ANC */ - alc_write_coef_idx(codec, 0x34, 0xa0c0); - /* AGC MUX */ - alc_update_coef_idx(codec, 0x16, 0x0008, 0); - /* DAC simple content protection */ - alc_update_coef_idx(codec, 0x1d, 0x00e0, 0); - /* ADC simple content protection */ - alc_update_coef_idx(codec, 0x1f, 0x00e0, 0); - /* DAC ADC Zero Detection */ - alc_write_coef_idx(codec, 0x21, 0x8804); - /* PLL */ - alc_write_coef_idx(codec, 0x63, 0x2902); - /* capless control 2 */ - alc_write_coef_idx(codec, 0x68, 0xa080); - /* capless control 3 */ - alc_write_coef_idx(codec, 0x69, 0x3400); - /* capless control 4 */ - alc_write_coef_idx(codec, 0x6a, 0x2f3e); - /* capless control 5 */ - alc_write_coef_idx(codec, 0x6b, 0x0); - /* class D test 2 */ - alc_update_coef_idx(codec, 0x6d, 0x0fff, 0x0900); - /* class D test 3 */ - alc_write_coef_idx(codec, 0x6e, 0x110a); - /* class D test 5 */ - alc_update_coef_idx(codec, 0x70, 0x00f8, 0x00d8); - /* class D test 6 */ - alc_write_coef_idx(codec, 0x71, 0x0014); - /* classD OCP */ - alc_write_coef_idx(codec, 0x72, 0xc2ba); - /* classD pure DC test */ - alc_update_coef_idx(codec, 0x77, 0x0f80, 0); - /* Class D amp control */ - alc_write_coef_idx(codec, 0x6c, 0xfc06); + alc_process_coef_fw(codec, alc282_coefs); } static void alc282_init(struct hda_codec *codec) @@ -2922,72 +2924,45 @@ static void alc282_shutup(struct hda_codec *codec) alc_write_coef_idx(codec, 0x78, coef78); } +static struct coef_fw alc283_coefs[] = { + WRITE_COEF(0x03, 0x0002), /* Power Down Control */ + WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */ + WRITE_COEF(0x07, 0x0200), /* DMIC control */ + UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ + UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ + WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */ + WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */ + WRITE_COEF(0x0e, 0x6fc0), /* LDO1/2/3, DAC/ADC */ + UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */ + UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */ + WRITE_COEF(0x3a, 0x0), /* Class D test 4 */ + UPDATE_COEF(0x0c, 0xfe00, 0x0), /* IO power down directly */ + WRITE_COEF(0x22, 0xa0c0), /* ANC */ + UPDATE_COEFEX(0x53, 0x01, 0x000f, 0x0008), /* AGC MUX */ + UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */ + UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */ + WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */ + WRITE_COEF(0x2e, 0x2902), /* PLL */ + WRITE_COEF(0x33, 0xa080), /* capless control 2 */ + WRITE_COEF(0x34, 0x3400), /* capless control 3 */ + WRITE_COEF(0x35, 0x2f3e), /* capless control 4 */ + WRITE_COEF(0x36, 0x0), /* capless control 5 */ + UPDATE_COEF(0x38, 0x0fff, 0x0900), /* class D test 2 */ + WRITE_COEF(0x39, 0x110a), /* class D test 3 */ + UPDATE_COEF(0x3b, 0x00f8, 0x00d8), /* class D test 5 */ + WRITE_COEF(0x3c, 0x0014), /* class D test 6 */ + WRITE_COEF(0x3d, 0xc2ba), /* classD OCP */ + UPDATE_COEF(0x42, 0x0f80, 0x0), /* classD pure DC test */ + WRITE_COEF(0x49, 0x0), /* test mode */ + UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */ + UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */ + WRITE_COEF(0x37, 0xfc06), /* Class D amp control */ + {} +}; + static void alc283_restore_default_value(struct hda_codec *codec) { - /* Power Down Control */ - alc_write_coef_idx(codec, 0x03, 0x0002); - /* FIFO and filter clock */ - alc_write_coef_idx(codec, 0x05, 0x0700); - /* DMIC control */ - alc_write_coef_idx(codec, 0x07, 0x0200); - /* Analog clock */ - alc_update_coef_idx(codec, 0x06, 0x00f0, 0); - /* JD */ - alc_update_coef_idx(codec, 0x08, 0xfffc, 0x0c2c); - /* JD offset1 */ - alc_write_coef_idx(codec, 0x0a, 0xcccc); - /* JD offset2 */ - alc_write_coef_idx(codec, 0x0b, 0xcccc); - /* LDO1/2/3, DAC/ADC */ - alc_write_coef_idx(codec, 0x0e, 0x6fc0); - /* JD */ - alc_update_coef_idx(codec, 0x0f, 0xf800, 0x1000); - /* Capless */ - alc_update_coef_idx(codec, 0x10, 0xfc00, 0x0c00); - /* Class D test 4 */ - alc_write_coef_idx(codec, 0x3a, 0x0); - /* IO power down directly */ - alc_update_coef_idx(codec, 0x0c, 0xfe00, 0x0); - /* ANC */ - alc_write_coef_idx(codec, 0x22, 0xa0c0); - /* AGC MUX */ - alc_update_coefex_idx(codec, 0x53, 0x01, 0x000f, 0x0008); - /* DAC simple content protection */ - alc_update_coef_idx(codec, 0x1d, 0x00e0, 0x0); - /* ADC simple content protection */ - alc_update_coef_idx(codec, 0x1f, 0x00e0, 0x0); - /* DAC ADC Zero Detection */ - alc_write_coef_idx(codec, 0x21, 0x8804); - /* PLL */ - alc_write_coef_idx(codec, 0x2e, 0x2902); - /* capless control 2 */ - alc_write_coef_idx(codec, 0x33, 0xa080); - /* capless control 3 */ - alc_write_coef_idx(codec, 0x34, 0x3400); - /* capless control 4 */ - alc_write_coef_idx(codec, 0x35, 0x2f3e); - /* capless control 5 */ - alc_write_coef_idx(codec, 0x36, 0x0); - /* class D test 2 */ - alc_update_coef_idx(codec, 0x38, 0x0fff, 0x0900); - /* class D test 3 */ - alc_write_coef_idx(codec, 0x39, 0x110a); - /* class D test 5 */ - alc_update_coef_idx(codec, 0x3b, 0x00f8, 0x00d8); - /* class D test 6 */ - alc_write_coef_idx(codec, 0x3c, 0x0014); - /* classD OCP */ - alc_write_coef_idx(codec, 0x3d, 0xc2ba); - /* classD pure DC test */ - alc_update_coef_idx(codec, 0x42, 0x0f80, 0x0); - /* test mode */ - alc_write_coef_idx(codec, 0x49, 0x0); - /* Class D DC enable */ - alc_update_coef_idx(codec, 0x40, 0xf800, 0x9800); - /* DC offset */ - alc_update_coef_idx(codec, 0x42, 0xf000, 0x2000); - /* Class D amp control */ - alc_write_coef_idx(codec, 0x37, 0xfc06); + alc_process_coef_fw(codec, alc283_coefs); } static void alc283_init(struct hda_codec *codec) @@ -3530,52 +3505,62 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, static void alc_headset_mode_unplugged(struct hda_codec *codec) { + static struct coef_fw coef0255[] = { + WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */ + WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */ + UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ + WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */ + WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */ + {} + }; + static struct coef_fw coef0233[] = { + WRITE_COEF(0x1b, 0x0c0b), + WRITE_COEF(0x45, 0xc429), + UPDATE_COEF(0x35, 0x4000, 0), + WRITE_COEF(0x06, 0x2104), + WRITE_COEF(0x1a, 0x0001), + WRITE_COEF(0x26, 0x0004), + WRITE_COEF(0x32, 0x42a3), + {} + }; + static struct coef_fw coef0292[] = { + WRITE_COEF(0x76, 0x000e), + WRITE_COEF(0x6c, 0x2400), + WRITE_COEF(0x18, 0x7308), + WRITE_COEF(0x6b, 0xc429), + {} + }; + static struct coef_fw coef0293[] = { + UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */ + UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */ + UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */ + UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */ + WRITE_COEF(0x45, 0xc429), /* Set to TRS type */ + UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */ + {} + }; + static struct coef_fw coef0668[] = { + WRITE_COEF(0x15, 0x0d40), + WRITE_COEF(0xb7, 0x802b), + {} + }; + switch (codec->vendor_id) { case 0x10ec0255: - /* LDO and MISC control */ - alc_write_coef_idx(codec, 0x1b, 0x0c0b); - /* UAJ function set to menual mode */ - alc_write_coef_idx(codec, 0x45, 0xd089); - /* Direct Drive HP Amp control(Set to verb control)*/ - alc_update_coefex_idx(codec, 0x57, 0x05, 1<<14, 0); - /* Set MIC2 Vref gate with HP */ - alc_write_coef_idx(codec, 0x06, 0x6104); - /* Direct Drive HP Amp control */ - alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6); + alc_process_coef_fw(codec, coef0255); break; case 0x10ec0233: case 0x10ec0283: - alc_write_coef_idx(codec, 0x1b, 0x0c0b); - alc_write_coef_idx(codec, 0x45, 0xc429); - alc_update_coef_idx(codec, 0x35, 0x4000, 0); - alc_write_coef_idx(codec, 0x06, 0x2104); - alc_write_coef_idx(codec, 0x1a, 0x0001); - alc_write_coef_idx(codec, 0x26, 0x0004); - alc_write_coef_idx(codec, 0x32, 0x42a3); + alc_process_coef_fw(codec, coef0233); break; case 0x10ec0292: - alc_write_coef_idx(codec, 0x76, 0x000e); - alc_write_coef_idx(codec, 0x6c, 0x2400); - alc_write_coef_idx(codec, 0x18, 0x7308); - alc_write_coef_idx(codec, 0x6b, 0xc429); + alc_process_coef_fw(codec, coef0292); break; case 0x10ec0293: - /* SET Line1 JD to 0 */ - alc_update_coef_idx(codec, 0x10, 7<<8, 6<<8); - /* SET charge pump by verb */ - alc_update_coefex_idx(codec, 0x57, 0x05, 1<<15|1<<13, 0x0); - /* SET EN_OSW to 1 */ - alc_update_coefex_idx(codec, 0x57, 0x03, 1<<10, 1<<10); - /* Combo JD gating with LINE1-VREFO */ - alc_update_coef_idx(codec, 0x1a, 1<<3, 1<<3); - /* Set to TRS type */ - alc_write_coef_idx(codec, 0x45, 0xc429); - /* Combo Jack auto detect */ - alc_update_coef_idx(codec, 0x4a, 0x000f, 0x000e); + alc_process_coef_fw(codec, coef0293); break; case 0x10ec0668: - alc_write_coef_idx(codec, 0x15, 0x0d40); - alc_write_coef_idx(codec, 0xb7, 0x802b); + alc_process_coef_fw(codec, coef0668); break; } codec_dbg(codec, "Headset jack set to unplugged mode.\n"); @@ -3585,48 +3570,65 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, hda_nid_t mic_pin) { + static struct coef_fw coef0255[] = { + WRITE_COEFEX(0x57, 0x03, 0x8aa6), + WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */ + {} + }; + static struct coef_fw coef0233[] = { + UPDATE_COEF(0x35, 0, 1<<14), + WRITE_COEF(0x06, 0x2100), + WRITE_COEF(0x1a, 0x0021), + WRITE_COEF(0x26, 0x008c), + {} + }; + static struct coef_fw coef0292[] = { + WRITE_COEF(0x19, 0xa208), + WRITE_COEF(0x2e, 0xacf0), + {} + }; + static struct coef_fw coef0293[] = { + UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */ + UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */ + UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */ + {} + }; + static struct coef_fw coef0688[] = { + WRITE_COEF(0xb7, 0x802b), + WRITE_COEF(0xb5, 0x1040), + UPDATE_COEF(0xc3, 0, 1<<12), + {} + }; + switch (codec->vendor_id) { case 0x10ec0255: alc_write_coef_idx(codec, 0x45, 0xc489); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6); - /* Set MIC2 Vref gate to normal */ - alc_write_coef_idx(codec, 0x06, 0x6100); + alc_process_coef_fw(codec, coef0255); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; case 0x10ec0233: case 0x10ec0283: alc_write_coef_idx(codec, 0x45, 0xc429); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_update_coef_idx(codec, 0x35, 0, 1<<14); - alc_write_coef_idx(codec, 0x06, 0x2100); - alc_write_coef_idx(codec, 0x1a, 0x0021); - alc_write_coef_idx(codec, 0x26, 0x008c); + alc_process_coef_fw(codec, coef0233); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; case 0x10ec0292: snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_write_coef_idx(codec, 0x19, 0xa208); - alc_write_coef_idx(codec, 0x2e, 0xacf0); + alc_process_coef_fw(codec, coef0292); break; case 0x10ec0293: /* Set to TRS mode */ alc_write_coef_idx(codec, 0x45, 0xc429); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - /* SET charge pump by verb */ - alc_update_coefex_idx(codec, 0x57, 0x05, 0, 1<<15|1<<13); - /* SET EN_OSW to 0 */ - alc_update_coefex_idx(codec, 0x57, 0x03, 1<<10, 0); - /* Combo JD gating without LINE1-VREFO */ - alc_update_coef_idx(codec, 0x1a, 1<<3, 0); + alc_process_coef_fw(codec, coef0293); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_write_coef_idx(codec, 0xb7, 0x802b); - alc_write_coef_idx(codec, 0xb5, 0x1040); - alc_update_coef_idx(codec, 0xc3, 0, 1<<12); + alc_process_coef_fw(codec, coef0688); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; } @@ -3635,36 +3637,54 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, static void alc_headset_mode_default(struct hda_codec *codec) { + static struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xc089), + WRITE_COEF(0x45, 0xc489), + WRITE_COEFEX(0x57, 0x03, 0x8ea6), + WRITE_COEF(0x49, 0x0049), + {} + }; + static struct coef_fw coef0233[] = { + WRITE_COEF(0x06, 0x2100), + WRITE_COEF(0x32, 0x4ea3), + {} + }; + static struct coef_fw coef0292[] = { + WRITE_COEF(0x76, 0x000e), + WRITE_COEF(0x6c, 0x2400), + WRITE_COEF(0x6b, 0xc429), + WRITE_COEF(0x18, 0x7308), + {} + }; + static struct coef_fw coef0293[] = { + UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */ + WRITE_COEF(0x45, 0xC429), /* Set to TRS type */ + UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */ + {} + }; + static struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0041), + WRITE_COEF(0x15, 0x0d40), + WRITE_COEF(0xb7, 0x802b), + {} + }; + switch (codec->vendor_id) { case 0x10ec0255: - alc_write_coef_idx(codec, 0x45, 0xc089); - alc_write_coef_idx(codec, 0x45, 0xc489); - alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); - alc_write_coef_idx(codec, 0x49, 0x0049); + alc_process_coef_fw(codec, coef0255); break; case 0x10ec0233: case 0x10ec0283: - alc_write_coef_idx(codec, 0x06, 0x2100); - alc_write_coef_idx(codec, 0x32, 0x4ea3); + alc_process_coef_fw(codec, coef0233); break; case 0x10ec0292: - alc_write_coef_idx(codec, 0x76, 0x000e); - alc_write_coef_idx(codec, 0x6c, 0x2400); - alc_write_coef_idx(codec, 0x6b, 0xc429); - alc_write_coef_idx(codec, 0x18, 0x7308); + alc_process_coef_fw(codec, coef0292); break; case 0x10ec0293: - /* Combo Jack auto detect */ - alc_update_coef_idx(codec, 0x4a, 0x000f, 0x000e); - /* Set to TRS type */ - alc_write_coef_idx(codec, 0x45, 0xC429); - /* Combo JD gating without LINE1-VREFO */ - alc_update_coef_idx(codec, 0x1a, 1<<3, 0); + alc_process_coef_fw(codec, coef0293); break; case 0x10ec0668: - alc_write_coef_idx(codec, 0x11, 0x0041); - alc_write_coef_idx(codec, 0x15, 0x0d40); - alc_write_coef_idx(codec, 0xb7, 0x802b); + alc_process_coef_fw(codec, coef0688); break; } codec_dbg(codec, "Headset jack set to headphone (default) mode.\n"); @@ -3673,34 +3693,52 @@ static void alc_headset_mode_default(struct hda_codec *codec) /* Iphone type */ static void alc_headset_mode_ctia(struct hda_codec *codec) { + static struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */ + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEFEX(0x57, 0x03, 0x8ea6), + {} + }; + static struct coef_fw coef0233[] = { + WRITE_COEF(0x45, 0xd429), + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEF(0x32, 0x4ea3), + {} + }; + static struct coef_fw coef0292[] = { + WRITE_COEF(0x6b, 0xd429), + WRITE_COEF(0x76, 0x0008), + WRITE_COEF(0x18, 0x7388), + {} + }; + static struct coef_fw coef0293[] = { + WRITE_COEF(0x45, 0xd429), /* Set to ctia type */ + UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */ + {} + }; + static struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0001), + WRITE_COEF(0x15, 0x0d60), + WRITE_COEF(0xc3, 0x0000), + {} + }; + switch (codec->vendor_id) { case 0x10ec0255: - /* Set to CTIA type */ - alc_write_coef_idx(codec, 0x45, 0xd489); - alc_write_coef_idx(codec, 0x1b, 0x0c2b); - alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); + alc_process_coef_fw(codec, coef0255); break; case 0x10ec0233: case 0x10ec0283: - alc_write_coef_idx(codec, 0x45, 0xd429); - alc_write_coef_idx(codec, 0x1b, 0x0c2b); - alc_write_coef_idx(codec, 0x32, 0x4ea3); + alc_process_coef_fw(codec, coef0233); break; case 0x10ec0292: - alc_write_coef_idx(codec, 0x6b, 0xd429); - alc_write_coef_idx(codec, 0x76, 0x0008); - alc_write_coef_idx(codec, 0x18, 0x7388); + alc_process_coef_fw(codec, coef0292); break; case 0x10ec0293: - /* Set to ctia type */ - alc_write_coef_idx(codec, 0x45, 0xd429); - /* SET Line1 JD to 1 */ - alc_update_coef_idx(codec, 0x10, 7<<8, 7<<8); + alc_process_coef_fw(codec, coef0293); break; case 0x10ec0668: - alc_write_coef_idx(codec, 0x11, 0x0001); - alc_write_coef_idx(codec, 0x15, 0x0d60); - alc_write_coef_idx(codec, 0xc3, 0x0000); + alc_process_coef_fw(codec, coef0688); break; } codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); @@ -3709,34 +3747,52 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) /* Nokia type */ static void alc_headset_mode_omtp(struct hda_codec *codec) { + static struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */ + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEFEX(0x57, 0x03, 0x8ea6), + {} + }; + static struct coef_fw coef0233[] = { + WRITE_COEF(0x45, 0xe429), + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEF(0x32, 0x4ea3), + {} + }; + static struct coef_fw coef0292[] = { + WRITE_COEF(0x6b, 0xe429), + WRITE_COEF(0x76, 0x0008), + WRITE_COEF(0x18, 0x7388), + {} + }; + static struct coef_fw coef0293[] = { + WRITE_COEF(0x45, 0xe429), /* Set to omtp type */ + UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */ + {} + }; + static struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0001), + WRITE_COEF(0x15, 0x0d50), + WRITE_COEF(0xc3, 0x0000), + {} + }; + switch (codec->vendor_id) { case 0x10ec0255: - /* Set to OMTP Type */ - alc_write_coef_idx(codec, 0x45, 0xe489); - alc_write_coef_idx(codec, 0x1b, 0x0c2b); - alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); + alc_process_coef_fw(codec, coef0255); break; case 0x10ec0233: case 0x10ec0283: - alc_write_coef_idx(codec, 0x45, 0xe429); - alc_write_coef_idx(codec, 0x1b, 0x0c2b); - alc_write_coef_idx(codec, 0x32, 0x4ea3); + alc_process_coef_fw(codec, coef0233); break; case 0x10ec0292: - alc_write_coef_idx(codec, 0x6b, 0xe429); - alc_write_coef_idx(codec, 0x76, 0x0008); - alc_write_coef_idx(codec, 0x18, 0x7388); + alc_process_coef_fw(codec, coef0292); break; case 0x10ec0293: - /* Set to omtp type */ - alc_write_coef_idx(codec, 0x45, 0xe429); - /* SET Line1 JD to 1 */ - alc_update_coef_idx(codec, 0x10, 7<<8, 7<<8); + alc_process_coef_fw(codec, coef0293); break; case 0x10ec0668: - alc_write_coef_idx(codec, 0x11, 0x0001); - alc_write_coef_idx(codec, 0x15, 0x0d50); - alc_write_coef_idx(codec, 0xc3, 0x0000); + alc_process_coef_fw(codec, coef0688); break; } codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); @@ -3747,13 +3803,28 @@ static void alc_determine_headset_type(struct hda_codec *codec) int val; bool is_ctia = false; struct alc_spec *spec = codec->spec; + static struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/ + WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref + conteol) */ + {} + }; + static struct coef_fw coef0293[] = { + UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */ + WRITE_COEF(0x45, 0xD429), /* Set to ctia type */ + {} + }; + static struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0001), + WRITE_COEF(0xb7, 0x802b), + WRITE_COEF(0x15, 0x0d60), + WRITE_COEF(0xc3, 0x0c00), + {} + }; switch (codec->vendor_id) { case 0x10ec0255: - /* combo jack auto switch control(Check type)*/ - alc_write_coef_idx(codec, 0x45, 0xd089); - /* combo jack auto switch control(Vref conteol) */ - alc_write_coef_idx(codec, 0x49, 0x0149); + alc_process_coef_fw(codec, coef0255); msleep(300); val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x0070) == 0x0070; @@ -3772,19 +3843,13 @@ static void alc_determine_headset_type(struct hda_codec *codec) is_ctia = (val & 0x001c) == 0x001c; break; case 0x10ec0293: - /* Combo Jack auto detect */ - alc_update_coef_idx(codec, 0x4a, 0x000f, 0x0008); - /* Set to ctia type */ - alc_write_coef_idx(codec, 0x45, 0xD429); + alc_process_coef_fw(codec, coef0293); msleep(300); val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x0070) == 0x0070; break; case 0x10ec0668: - alc_write_coef_idx(codec, 0x11, 0x0001); - alc_write_coef_idx(codec, 0xb7, 0x802b); - alc_write_coef_idx(codec, 0x15, 0x0d60); - alc_write_coef_idx(codec, 0xc3, 0x0c00); + alc_process_coef_fw(codec, coef0688); msleep(300); val = alc_read_coef_idx(codec, 0xbe); is_ctia = (val & 0x1c02) == 0x1c02; @@ -3920,11 +3985,15 @@ static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec, static void alc255_set_default_jack_type(struct hda_codec *codec) { /* Set to iphone type */ - alc_write_coef_idx(codec, 0x1b, 0x880b); - alc_write_coef_idx(codec, 0x45, 0xd089); - alc_write_coef_idx(codec, 0x1b, 0x080b); - alc_write_coef_idx(codec, 0x46, 0x0004); - alc_write_coef_idx(codec, 0x1b, 0x0c0b); + static struct coef_fw fw[] = { + WRITE_COEF(0x1b, 0x880b), + WRITE_COEF(0x45, 0xd089), + WRITE_COEF(0x1b, 0x080b), + WRITE_COEF(0x46, 0x0004), + WRITE_COEF(0x1b, 0x0c0b), + {} + }; + alc_process_coef_fw(codec, fw); msleep(30); } -- GitLab From b22ae40ef2e7847ddbd802d1a887188e113675f3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Aug 2014 17:23:07 +0200 Subject: [PATCH 0376/5088] Documentation: kbuild: Remove obsolete include/asm symlink step As of commit f7f16b7799ed68654850ab340ef812895aebcf4c ("kbuild: drop include/asm"), the include/asm symlink is no longer created. Signed-off-by: Geert Uytterhoeven Signed-off-by: Michal Marek --- Documentation/kbuild/makefiles.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 764f5991a3fc..a445e1c8828e 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -818,17 +818,16 @@ a few targets. When kbuild executes, the following steps are followed (roughly): 1) Configuration of the kernel => produce .config 2) Store kernel version in include/linux/version.h -3) Symlink include/asm to include/asm-$(ARCH) -4) Updating all other prerequisites to the target prepare: +3) Updating all other prerequisites to the target prepare: - Additional prerequisites are specified in arch/$(ARCH)/Makefile -5) Recursively descend down in all directories listed in +4) Recursively descend down in all directories listed in init-* core* drivers-* net-* libs-* and build all targets. - The values of the above variables are expanded in arch/$(ARCH)/Makefile. -6) All object files are then linked and the resulting file vmlinux is +5) All object files are then linked and the resulting file vmlinux is located at the root of the obj tree. The very first objects linked are listed in head-y, assigned by arch/$(ARCH)/Makefile. -7) Finally, the architecture-specific part does any required post processing +6) Finally, the architecture-specific part does any required post processing and builds the final bootimage. - This includes building boot records - Preparing initrd images and the like -- GitLab From ef80f0a1e033bcab17257e2155a3c9263a0919c1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Aug 2014 17:23:08 +0200 Subject: [PATCH 0377/5088] Documentation: kbuild: Improve if_changed documentation - These days if_changed is used with many more commands than ld, objcopy, and gzip, hence add an ellipsis, - Any target that utilises if_changed must be listed in $(targets), so it needs an assignment to "targets", not "target". Signed-off-by: Geert Uytterhoeven Signed-off-by: Michal Marek --- Documentation/kbuild/makefiles.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index a445e1c8828e..520b2c75bc56 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -1092,7 +1092,7 @@ When kbuild executes, the following steps are followed (roughly): Usage: target: source(s) FORCE - $(call if_changed,ld/objcopy/gzip) + $(call if_changed,ld/objcopy/gzip/...) When the rule is evaluated, it is checked to see if any files need an update, or the command line has changed since the last @@ -1110,7 +1110,7 @@ When kbuild executes, the following steps are followed (roughly): significant; for instance, the below will fail (note the extra space after the comma): target: source(s) FORCE - #WRONG!# $(call if_changed, ld/objcopy/gzip) + #WRONG!# $(call if_changed, ld/objcopy/gzip/...) ld Link target. Often, LDFLAGS_$@ is used to set specific options to ld. @@ -1142,7 +1142,7 @@ When kbuild executes, the following steps are followed (roughly): The ": %: %.o" part of the prerequisite is a shorthand that free us from listing the setup.o and bootsect.o files. - Note: It is a common mistake to forget the "target :=" assignment, + Note: It is a common mistake to forget the "targets :=" assignment, resulting in the target file being recompiled for no obvious reason. -- GitLab From cf6c53db9525a7f6c5052ccd84a0638128f14632 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Aug 2014 17:23:09 +0200 Subject: [PATCH 0378/5088] Documentation: kbuild: Remove obsolete dtc_cpp section Commit b40b25fff8205dd18124d8fc87b2c9c57f269b5f ("kbuild: always run gcc -E on *.dts, remove cmd_dtc_cpp") improved the functionality of cmd_dtc_cpp and merged it back into cmd_dtc. Signed-off-by: Geert Uytterhoeven Signed-off-by: Michal Marek --- Documentation/kbuild/makefiles.txt | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 520b2c75bc56..eda00a1073a7 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -1163,29 +1163,6 @@ When kbuild executes, the following steps are followed (roughly): clean-files += *.dtb DTC_FLAGS ?= -p 1024 - dtc_cpp - This is just like dtc as describe above, except that the C pre- - processor is invoked upon the .dtsp file before compiling the result - with dtc. - - In order for build dependencies to work, all files compiled using - dtc_cpp must use the C pre-processor's #include functionality and not - dtc's /include/ functionality. - - Using the C pre-processor allows use of #define to create named - constants. In turn, the #defines will typically appear in a header - file, which may be shared with regular C code. Since the dtc language - represents a data structure rather than code in C syntax, similar - restrictions are placed on a header file included by a device tree - file as for a header file included by an assembly language file. - In particular, the C pre-processor is passed -x assembler-with-cpp, - which sets macro __ASSEMBLY__. __DTS__ is also set. These allow header - files to restrict their content to that compatible with device tree - source. - - A central rule exists to create $(obj)/%.dtb from $(src)/%.dtsp; - architecture Makefiles do no need to explicitly write out that rule. - --- 6.8 Custom kbuild commands When kbuild is executing with KBUILD_VERBOSE=0, then only a shorthand -- GitLab From 39fed7015cd9124b5893fce18d33f49db1c48bea Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Aug 2014 17:23:10 +0200 Subject: [PATCH 0379/5088] Documentation: kbuild: Improve grammar - singular versus plural, - "by" versus "of", - missing "if", "it", "the", - consistent use of "xxx-specific" versus "xxx specific". Signed-off-by: Geert Uytterhoeven Acked-by: Randy Dunlap Signed-off-by: Michal Marek --- Documentation/kbuild/makefiles.txt | 56 +++++++++++++++--------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index eda00a1073a7..a311db829e9b 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -174,7 +174,7 @@ more details, with real examples. --- 3.3 Loadable module goals - obj-m - $(obj-m) specify object files which are built as loadable + $(obj-m) specifies object files which are built as loadable kernel modules. A module may be built from one source file or several source @@ -277,7 +277,7 @@ more details, with real examples. down in the ext2 directory. Kbuild only uses this information to decide that it needs to visit the directory, it is the Makefile in the subdirectory that - specifies what is modules and what is built-in. + specifies what is modular and what is built-in. It is good practice to use a CONFIG_ variable when assigning directory names. This allows kbuild to totally skip the directory if the @@ -403,7 +403,7 @@ more details, with real examples. echoing information to user in a rule is often a good practice but when execution "make -s" one does not expect to see any output except for warnings/errors. - To support this kbuild define $(kecho) which will echo out the + To support this kbuild defines $(kecho) which will echo out the text following $(kecho) to stdout except if "make -s" is used. Example: @@ -417,7 +417,7 @@ more details, with real examples. The kernel may be built with several different versions of $(CC), each supporting a unique set of features and options. - kbuild provide basic support to check for valid options for $(CC). + kbuild provides basic support to check for valid options for $(CC). $(CC) is usually the gcc compiler, but other alternatives are available. @@ -456,8 +456,8 @@ more details, with real examples. Note: as-instr-option uses KBUILD_AFLAGS for $(AS) options cc-option - cc-option is used to check if $(CC) supports a given option, and not - supported to use an optional second option. + cc-option is used to check if $(CC) supports a given option, and if + not supported to use an optional second option. Example: #arch/x86/Makefile @@ -557,8 +557,8 @@ more details, with real examples. false ; \ fi - In this example for a specific GCC version the build will error out explaining - to the user why it stops. + In this example for a specific GCC version the build will error out + explaining to the user why it stops. cc-cross-prefix cc-cross-prefix is used to check if there exists a $(CC) in path with @@ -656,7 +656,7 @@ Both possibilities are described in the following. In the example above the executable is composed of the C++ file qconf.cc - identified by $(qconf-cxxobjs). - If qconf is composed by a mixture of .c and .cc files, then an + If qconf is composed of a mixture of .c and .cc files, then an additional line can be used to identify this. Example: @@ -733,7 +733,7 @@ Both possibilities are described in the following. hostprogs-$(CONFIG_KALLSYMS) += kallsyms Kbuild knows about both 'y' for built-in and 'm' for module. - So if a config symbol evaluate to 'm', kbuild will still build + So if a config symbol evaluates to 'm', kbuild will still build the binary. In other words, Kbuild handles hostprogs-m exactly like hostprogs-y. But only hostprogs-y is recommended to be used when no CONFIG symbols are involved. @@ -754,8 +754,8 @@ Additional files can be specified in kbuild makefiles by use of $(clean-files). #drivers/pci/Makefile clean-files := devlist.h classlist.h -When executing "make clean", the two files "devlist.h classlist.h" will -be deleted. Kbuild will assume files to be in same relative directory as the +When executing "make clean", the two files "devlist.h classlist.h" will be +deleted. Kbuild will assume files to be in the same relative directory as the Makefile except if an absolute path is specified (path starting with '/'). To delete a directory hierarchy use: @@ -786,7 +786,7 @@ is not sufficient this sometimes needs to be explicit. The above assignment instructs kbuild to descend down in the directory compressed/ when "make clean" is executed. -To support the clean infrastructure in the Makefiles that builds the +To support the clean infrastructure in the Makefiles that build the final bootimage there is an optional target named archclean: Example: @@ -926,7 +926,7 @@ When kbuild executes, the following steps are followed (roughly): KBUILD_AFLAGS_MODULE Options for $(AS) when building modules - $(KBUILD_AFLAGS_MODULE) is used to add arch specific options that + $(KBUILD_AFLAGS_MODULE) is used to add arch-specific options that are used for $(AS). From commandline AFLAGS_MODULE shall be used (see kbuild.txt). @@ -937,13 +937,13 @@ When kbuild executes, the following steps are followed (roughly): KBUILD_CFLAGS_MODULE Options for $(CC) when building modules - $(KBUILD_CFLAGS_MODULE) is used to add arch specific options that + $(KBUILD_CFLAGS_MODULE) is used to add arch-specific options that are used for $(CC). From commandline CFLAGS_MODULE shall be used (see kbuild.txt). KBUILD_LDFLAGS_MODULE Options for $(LD) when linking modules - $(KBUILD_LDFLAGS_MODULE) is used to add arch specific options + $(KBUILD_LDFLAGS_MODULE) is used to add arch-specific options used when linking modules. This is often a linker script. From commandline LDFLAGS_MODULE shall be used (see kbuild.txt). @@ -1065,7 +1065,7 @@ When kbuild executes, the following steps are followed (roughly): extra-y - extra-y specify additional targets created in the current + extra-y specifies additional targets created in the current directory, in addition to any targets specified by obj-*. Listing all targets in extra-y is required for two purposes: @@ -1141,7 +1141,7 @@ When kbuild executes, the following steps are followed (roughly): 2) delete target during make clean The ": %: %.o" part of the prerequisite is a shorthand that - free us from listing the setup.o and bootsect.o files. + frees us from listing the setup.o and bootsect.o files. Note: It is a common mistake to forget the "targets :=" assignment, resulting in the target file being recompiled for no obvious reason. @@ -1213,11 +1213,11 @@ When kbuild executes, the following steps are followed (roughly): When building the *.lds target, kbuild uses the variables: KBUILD_CPPFLAGS : Set in top-level Makefile cppflags-y : May be set in the kbuild makefile - CPPFLAGS_$(@F) : Target specific flags. + CPPFLAGS_$(@F) : Target-specific flags. Note that the full filename is used in this assignment. - The kbuild infrastructure for *lds file are used in several + The kbuild infrastructure for *lds files is used in several architecture-specific files. --- 6.10 Generic header files @@ -1230,11 +1230,11 @@ When kbuild executes, the following steps are followed (roughly): === 7 Kbuild syntax for exported headers -The kernel include a set of headers that is exported to userspace. +The kernel includes a set of headers that is exported to userspace. Many headers can be exported as-is but other headers require a minimal pre-processing before they are ready for user-space. The pre-processing does: -- drop kernel specific annotations +- drop kernel-specific annotations - drop include of compiler.h - drop all sections that are kernel internal (guarded by ifdef __KERNEL__) @@ -1244,7 +1244,7 @@ See subsequent chapter for the syntax of the Kbuild file. --- 7.1 header-y - header-y specify header files to be exported. + header-y specifies header files to be exported. Example: #include/linux/Kbuild @@ -1254,7 +1254,7 @@ See subsequent chapter for the syntax of the Kbuild file. The convention is to list one file per line and preferably in alphabetic order. - header-y also specify which subdirectories to visit. + header-y also specifies which subdirectories to visit. A subdirectory is identified by a trailing '/' which can be seen in the example above for the usb subdirectory. @@ -1272,9 +1272,9 @@ See subsequent chapter for the syntax of the Kbuild file. --- 7.3 destination-y - When an architecture have a set of exported headers that needs to be + When an architecture has a set of exported headers that needs to be exported to a different directory destination-y is used. - destination-y specify the destination directory for all exported + destination-y specifies the destination directory for all exported headers in the file where it is present. Example: @@ -1367,9 +1367,9 @@ The top Makefile exports the following variables: INSTALL_MOD_STRIP - If this variable is specified, will cause modules to be stripped + If this variable is specified, it will cause modules to be stripped after they are installed. If INSTALL_MOD_STRIP is '1', then the - default option --strip-debug will be used. Otherwise, + default option --strip-debug will be used. Otherwise, the INSTALL_MOD_STRIP value will be used as the option(s) to the strip command. -- GitLab From c8589d1e9e01debdb4f574afe7c585714353ad79 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 19 Aug 2014 16:34:20 +0900 Subject: [PATCH 0380/5088] kbuild: handle multi-objs dependency appropriately The comment in scripts/Makefile.build says as follows: We would rather have a list of rules like foo.o: $(foo-objs) but that's not so easy, so we rather make all composite objects depend on the set of all their parts This commit makes it possible! For example, assume a Makefile like this obj-m = foo.o bar.o foo-objs := foo1.o foo2.o bar-objs := bar1.o bar2.o Without this patch, foo.o depends on all of foo1.o foo2.o bar1.o bar2.o. It looks funny that foo.o is regenerated when bar1.c is updated. Now we can handle the dependency of foo.o and bar.o separately. Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- scripts/Makefile.build | 10 ++++------ scripts/Makefile.lib | 9 +++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index bf3e6778cd71..5b09d3637855 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -382,16 +382,14 @@ cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalys quiet_cmd_link_multi-m = LD [M] $@ cmd_link_multi-m = $(cmd_link_multi-y) -# We would rather have a list of rules like -# foo.o: $(foo-objs) -# but that's not so easy, so we rather make all composite objects depend -# on the set of all their parts -$(multi-used-y) : %.o: $(multi-objs-y) FORCE +$(multi-used-y): FORCE $(call if_changed,link_multi-y) +$(call multi_depend, $(multi-used-y), .o, -objs -y) -$(multi-used-m) : %.o: $(multi-objs-m) FORCE +$(multi-used-m): FORCE $(call if_changed,link_multi-m) @{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod) +$(call multi_depend, $(multi-used-m), .o, -objs -y) targets += $(multi-used-y) $(multi-used-m) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 260bf8acfce9..54be19a0fa51 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -159,6 +159,15 @@ dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \ modname-multi = $(sort $(foreach m,$(multi-used),\ $(if $(filter $(subst $(obj)/,,$*.o), $($(m:.o=-objs)) $($(m:.o=-y))),$(m:.o=)))) +# Useful for describing the dependency of composite objects +# Usage: +# $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add) +define multi_depend +$(foreach m, $(notdir $1), \ + $(eval $(obj)/$m: \ + $(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s))))))) +endef + ifdef REGENERATE_PARSERS # GPERF -- GitLab From 97e3226e6e984c8cd9bed47010f30827a3ce816a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 19 Aug 2014 16:34:21 +0900 Subject: [PATCH 0381/5088] kbuild: handle the dependency of multi-objs hostprogs appropriately Assume we have a Makefile like: hostprogs-y := foo bar foo-objs := foo1.o foo2.o bar-objs := bar1.o bar2.o Without this commit, the host program foo depends on all of foo1.o foo2.o bar1.o bar2.o. This commit allows to handle the dependency of each host program separately. Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- scripts/Makefile.host | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/Makefile.host b/scripts/Makefile.host index ab5980f91714..133edfae5b8a 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -96,8 +96,9 @@ quiet_cmd_host-cmulti = HOSTLD $@ cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \ $(addprefix $(obj)/,$($(@F)-objs)) \ $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) -$(host-cmulti): $(obj)/%: $(host-cobjs) FORCE +$(host-cmulti): FORCE $(call if_changed,host-cmulti) +$(call multi_depend, $(host-cmulti), , -objs) # Create .o file from a single .c file # host-cobjs -> .o @@ -113,8 +114,9 @@ quiet_cmd_host-cxxmulti = HOSTLD $@ $(foreach o,objs cxxobjs,\ $(addprefix $(obj)/,$($(@F)-$(o)))) \ $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) -$(host-cxxmulti): $(obj)/%: $(host-cobjs) $(host-cxxobjs) FORCE +$(host-cxxmulti): FORCE $(call if_changed,host-cxxmulti) +$(call multi_depend, $(host-cxxmulti), , -objs -cxxobjs) # Create .o file from a single .cc (C++) file quiet_cmd_host-cxxobjs = HOSTCXX $@ -- GitLab From 022af62d0190e1e3db63c19aeb5f51ae0612cd71 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 19 Aug 2014 16:34:22 +0900 Subject: [PATCH 0382/5088] kbuild: refactor script/kconfig/Makefile Now it is harmless to add all host programs to hostprogs-y. Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- scripts/kconfig/Makefile | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 9c4d2412fb72..76f6171768e4 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -157,35 +157,7 @@ qconf-cxxobjs := qconf.o qconf-objs := zconf.tab.o gconf-objs := gconf.o zconf.tab.o -hostprogs-y := conf - -ifeq ($(MAKECMDGOALS),nconfig) - hostprogs-y += nconf -endif - -ifeq ($(MAKECMDGOALS),menuconfig) - hostprogs-y += mconf -endif - -ifeq ($(MAKECMDGOALS),update-po-config) - hostprogs-y += kxgettext -endif - -ifeq ($(MAKECMDGOALS),xconfig) - qconf-target := 1 -endif -ifeq ($(MAKECMDGOALS),gconfig) - gconf-target := 1 -endif - - -ifeq ($(qconf-target),1) - hostprogs-y += qconf -endif - -ifeq ($(gconf-target),1) - hostprogs-y += gconf -endif +hostprogs-y := conf nconf mconf kxgettext qconf gconf clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h @@ -224,7 +196,7 @@ HOSTLOADLIBES_nconf = $(shell \ || echo "-lmenu -lpanel -lncurses" ) $(obj)/qconf.o: $(obj)/.tmp_qtcheck -ifeq ($(qconf-target),1) +ifeq ($(MAKECMDGOALS),xconfig) $(obj)/.tmp_qtcheck: $(src)/Makefile -include $(obj)/.tmp_qtcheck @@ -281,7 +253,7 @@ endif $(obj)/gconf.o: $(obj)/.tmp_gtkcheck -ifeq ($(gconf-target),1) +ifeq ($(MAKECMDGOALS),gconfig) -include $(obj)/.tmp_gtkcheck # GTK needs some extra effort, too... -- GitLab From 221ecca6cafefbb5106cfc8bf9f1105233a33745 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 19 Aug 2014 16:34:23 +0900 Subject: [PATCH 0383/5088] kbuild: remove redundant clean-files from scripts/kconfig/Makefile Now mconf, qconf, gconf, nconf are always added to hostprogs-y. Files added to hostprogs-y are removed by "make clean". Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- scripts/kconfig/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 76f6171768e4..e7bf38e92007 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -161,7 +161,6 @@ hostprogs-y := conf nconf mconf kxgettext qconf gconf clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h -clean-files += mconf qconf gconf nconf clean-files += config.pot linux.pot # Check that we have the required ncurses stuff installed for lxdialog (menuconfig) -- GitLab From 8bf4abaddd01aa6c9d13804fa05084cb28135a47 Mon Sep 17 00:00:00 2001 From: Dirk Gouders Date: Sat, 16 Aug 2014 07:56:56 +0200 Subject: [PATCH 0384/5088] scripts/tags.sh: Don't specify kind-spec for emacs' ctags/etags Emacs' ctags/etags don't know about kind-spec in --regex and produce warnings: etags: invalid regexp modifier `v', ignoring etags: invalid regexp modifier `/', ignoring Fix it by removing kind-spec for the emacs case. Signed-off-by: Dirk Gouders Inspired-by: Masatake YAMATO Tested-by: Masatake YAMATO Signed-off-by: Michal Marek --- scripts/tags.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tags.sh b/scripts/tags.sh index cbfd269a6011..727989757d59 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -263,7 +263,7 @@ emacs() --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' \ --regex='/PCI_OP_READ(\([a-z]*[a-z]\).*[1-4])/pci_bus_read_config_\1/' \ --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'\ - --regex='/DEFINE_HASHTABLE\((\w*)/\1/v/' + --regex='/DEFINE_HASHTABLE\((\w*)/\1/' all_kconfigs | xargs $1 -a \ --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' -- GitLab From a60113d6a7fca3320e84d25db84c3c1a5a02b505 Mon Sep 17 00:00:00 2001 From: Dirk Gouders Date: Sat, 16 Aug 2014 07:56:57 +0200 Subject: [PATCH 0385/5088] scripts/tags.sh: remove *PCGFLAGS regular expressions Commit 0a31bc97c80c3fa8 (mm: memcontrol: rewrite uncharge API) removed the macros {TEST,SET,CLEAR,TESTCLEAR}PCFLAG. Remove corresponding entries from tags.sh -- in the emacs case they also produced warnigs because of unmatched '\('. Signed-off-by: Dirk Gouders Inspired-by: Masatake YAMATO Signed-off-by: Michal Marek --- scripts/tags.sh | 8 -------- 1 file changed, 8 deletions(-) diff --git a/scripts/tags.sh b/scripts/tags.sh index 727989757d59..0f61bd7ee958 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -193,10 +193,6 @@ exuberant() --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \ --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ - --regex-c++='/TESTPCGFLAG\(([^,)]*).*/PageCgroup\1/' \ - --regex-c++='/SETPCGFLAG\(([^,)]*).*/SetPageCgroup\1/' \ - --regex-c++='/CLEARPCGFLAG\(([^,)]*).*/ClearPageCgroup\1/' \ - --regex-c++='/TESTCLEARPCGFLAG\(([^,)]*).*/TestClearPageCgroup\1/' \ --regex-c='/PCI_OP_READ\((\w*).*[1-4]\)/pci_bus_read_config_\1/' \ --regex-c='/PCI_OP_WRITE\((\w*).*[1-4]\)/pci_bus_write_config_\1/' \ --regex-c='/DEFINE_(MUTEX|SEMAPHORE|SPINLOCK)\((\w*)/\2/v/' \ @@ -256,10 +252,6 @@ emacs() --regex='/__CLEARPAGEFLAG_NOOP(\([^,)]*\).*/__ClearPage\1/' \ --regex='/TESTCLEARFLAG_FALSE(\([^,)]*\).*/TestClearPage\1/' \ --regex='/__TESTCLEARFLAG_FALSE(\([^,)]*\).*/__TestClearPage\1/' \ - --regex='/TESTPCGFLAG\(([^,)]*).*/PageCgroup\1/' \ - --regex='/SETPCGFLAG\(([^,)]*).*/SetPageCgroup\1/' \ - --regex='/CLEARPCGFLAG\(([^,)]*).*/ClearPageCgroup\1/' \ - --regex='/TESTCLEARPCGFLAG\(([^,)]*).*/TestClearPageCgroup\1/' \ --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' \ --regex='/PCI_OP_READ(\([a-z]*[a-z]\).*[1-4])/pci_bus_read_config_\1/' \ --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'\ -- GitLab From 8e170655b517ba49bf4d015008474bcc2f425b20 Mon Sep 17 00:00:00 2001 From: Dirk Gouders Date: Sat, 16 Aug 2014 07:56:58 +0200 Subject: [PATCH 0386/5088] scripts/tags.sh: fix DEFINE_HASHTABLE in emacs case The emacs --regex for DEFINE_HASHTABLE produced a warning because of an unmatched '\('. Further, the whole entry did not work, because the regex needs to match from the beginning of a line, including keywords like 'static'. Finally, '\w' should not be used, because it stops at underscores which are often part of variable names in C, resulting in wrong entries in the tags file. Signed-off-by: Dirk Gouders Inspired-by: Masatake YAMATO Signed-off-by: Michal Marek --- scripts/tags.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tags.sh b/scripts/tags.sh index 0f61bd7ee958..fd651f90a838 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -255,7 +255,7 @@ emacs() --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' \ --regex='/PCI_OP_READ(\([a-z]*[a-z]\).*[1-4])/pci_bus_read_config_\1/' \ --regex='/PCI_OP_WRITE(\([a-z]*[a-z]\).*[1-4])/pci_bus_write_config_\1/'\ - --regex='/DEFINE_HASHTABLE\((\w*)/\1/' + --regex='/[^#]*DEFINE_HASHTABLE(\([^,)]*\)/\1/' all_kconfigs | xargs $1 -a \ --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' -- GitLab From f171abab8f1a75797124be5aae8376e20e4852d9 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 4 Aug 2014 10:06:28 +0530 Subject: [PATCH 0387/5088] iommu/exynos: Fix trivial typos Fixed trivial typos and grammar to improve readability. Changed w/a to workaround. Signed-off-by: Sachin Kamat Acked-by: Randy Dunlap Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 51 ++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index d037e87a1fe5..74233186f6f7 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -32,7 +32,7 @@ typedef u32 sysmmu_iova_t; typedef u32 sysmmu_pte_t; -/* We does not consider super section mapping (16MB) */ +/* We do not consider super section mapping (16MB) */ #define SECT_ORDER 20 #define LPAGE_ORDER 16 #define SPAGE_ORDER 12 @@ -307,7 +307,7 @@ static void show_fault_information(const char *name, static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) { - /* SYSMMU is in blocked when interrupt occurred. */ + /* SYSMMU is in blocked state when interrupt occurred. */ struct sysmmu_drvdata *data = dev_id; enum exynos_sysmmu_inttype itype; sysmmu_iova_t addr = -1; @@ -567,8 +567,8 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, sysmmu_iova_t iova, /* * L2TLB invalidation required * 4KB page: 1 invalidation - * 64KB page: 16 invalidation - * 1MB page: 64 invalidation + * 64KB page: 16 invalidations + * 1MB page: 64 invalidations * because it is set-associative TLB * with 8-way and 64 sets. * 1MB page can be cached in one of all sets. @@ -714,7 +714,7 @@ static int exynos_iommu_domain_init(struct iommu_domain *domain) if (!priv->lv2entcnt) goto err_counter; - /* w/a of System MMU v3.3 to prevent caching 1MiB mapping */ + /* Workaround for System MMU v3.3 to prevent caching 1MiB mapping */ for (i = 0; i < NUM_LV1ENTRIES; i += 8) { priv->pgtable[i + 0] = ZERO_LV2LINK; priv->pgtable[i + 1] = ZERO_LV2LINK; @@ -861,14 +861,14 @@ static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *priv, pgtable_flush(sent, sent + 1); /* - * If pretched SLPD is a fault SLPD in zero_l2_table, FLPD cache - * may caches the address of zero_l2_table. This function - * replaces the zero_l2_table with new L2 page table to write - * valid mappings. + * If pre-fetched SLPD is a faulty SLPD in zero_l2_table, + * FLPD cache may cache the address of zero_l2_table. This + * function replaces the zero_l2_table with new L2 page table + * to write valid mappings. * Accessing the valid area may cause page fault since FLPD - * cache may still caches zero_l2_table for the valid area - * instead of new L2 page table that have the mapping - * information of the valid area + * cache may still cache zero_l2_table for the valid area + * instead of new L2 page table that has the mapping + * information of the valid area. * Thus any replacement of zero_l2_table with other valid L2 * page table must involve FLPD cache invalidation for System * MMU v3.3. @@ -963,27 +963,27 @@ static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t paddr, size_t size, /* * *CAUTION* to the I/O virtual memory managers that support exynos-iommu: * - * System MMU v3.x have an advanced logic to improve address translation + * System MMU v3.x has advanced logic to improve address translation * performance with caching more page table entries by a page table walk. - * However, the logic has a bug that caching fault page table entries and System - * MMU reports page fault if the cached fault entry is hit even though the fault - * entry is updated to a valid entry after the entry is cached. - * To prevent caching fault page table entries which may be updated to valid - * entries later, the virtual memory manager should care about the w/a about the - * problem. The followings describe w/a. + * However, the logic has a bug that while caching faulty page table entries, + * System MMU reports page fault if the cached fault entry is hit even though + * the fault entry is updated to a valid entry after the entry is cached. + * To prevent caching faulty page table entries which may be updated to valid + * entries later, the virtual memory manager should care about the workaround + * for the problem. The following describes the workaround. * * Any two consecutive I/O virtual address regions must have a hole of 128KiB - * in maximum to prevent misbehavior of System MMU 3.x. (w/a of h/w bug) + * at maximum to prevent misbehavior of System MMU 3.x (workaround for h/w bug). * - * Precisely, any start address of I/O virtual region must be aligned by + * Precisely, any start address of I/O virtual region must be aligned with * the following sizes for System MMU v3.1 and v3.2. * System MMU v3.1: 128KiB * System MMU v3.2: 256KiB * * Because System MMU v3.3 caches page table entries more aggressively, it needs - * more w/a. - * - Any two consecutive I/O virtual regions must be have a hole of larger size - * than or equal size to 128KiB. + * more workarounds. + * - Any two consecutive I/O virtual regions must have a hole of size larger + * than or equal to 128KiB. * - Start address of an I/O virtual region must be aligned by 128KiB. */ static int exynos_iommu_map(struct iommu_domain *domain, unsigned long l_iova, @@ -1061,7 +1061,8 @@ static size_t exynos_iommu_unmap(struct iommu_domain *domain, goto err; } - *ent = ZERO_LV2LINK; /* w/a for h/w bug in Sysmem MMU v3.3 */ + /* workaround for h/w bug in System MMU v3.3 */ + *ent = ZERO_LV2LINK; pgtable_flush(ent, ent + 1); size = SECT_SIZE; goto done; -- GitLab From f63ef69028742b09c1c0896177d555a30ff6cf13 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 11 Aug 2014 13:13:25 +0200 Subject: [PATCH 0388/5088] iommu/vt-d: Don't store SIRTP request Don't store the SIRTP request bit in the register state. It will otherwise become sticky and could request an Interrupt Remap Table Pointer update on each command register write. Found while starting to emulate IR in QEMU, not by observing problems on real hardware. Signed-off-by: Jan Kiszka Signed-off-by: Joerg Roedel --- drivers/iommu/intel_irq_remapping.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 0df41f6264f5..a872874c2565 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -438,8 +438,7 @@ static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode) (addr) | IR_X2APIC_MODE(mode) | INTR_REMAP_TABLE_REG_SIZE); /* Set interrupt-remapping table pointer */ - iommu->gcmd |= DMA_GCMD_SIRTP; - writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); + writel(iommu->gcmd | DMA_GCMD_SIRTP, iommu->reg + DMAR_GCMD_REG); IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_IRTPS), sts); -- GitLab From eecbad7d0306b9ee4f621517052913d1adaea753 Mon Sep 17 00:00:00 2001 From: Andreea-Cristina Bernat Date: Mon, 18 Aug 2014 15:20:56 +0300 Subject: [PATCH 0389/5088] iommu: Replace rcu_assign_pointer() with RCU_INIT_POINTER() The use of "rcu_assign_pointer()" is NULLing out the pointer. According to RCU_INIT_POINTER()'s block comment: "1. This use of RCU_INIT_POINTER() is NULLing out the pointer" it is better to use it instead of rcu_assign_pointer() because it has a smaller overhead. The following Coccinelle semantic patch was used: @@ @@ - rcu_assign_pointer + RCU_INIT_POINTER (..., NULL) Signed-off-by: Andreea-Cristina Bernat Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 60ab474bfff3..8ed55b0a1ce4 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -247,7 +247,7 @@ int dmar_remove_dev_scope(struct dmar_pci_notify_info *info, u16 segment, for_each_active_dev_scope(devices, count, index, tmp) if (tmp == &info->dev->dev) { - rcu_assign_pointer(devices[index].dev, NULL); + RCU_INIT_POINTER(devices[index].dev, NULL); synchronize_rcu(); put_device(tmp); return 1; -- GitLab From e5f81539f657af7e9f54ea37986fde8f92acef22 Mon Sep 17 00:00:00 2001 From: Feng Kan Date: Wed, 30 Jul 2014 14:56:58 -0700 Subject: [PATCH 0390/5088] irqchip: gic: Replace hex numbers with defines. This is to cleanup some hex numbers used in the code and replace them with defines to make the code cleaner. Signed-off-by: Feng Kan Reviewed-by: Anup Patel Link: https://lkml.kernel.org/r/1406757419-18729-2-git-send-email-fkan@apm.com Signed-off-by: Jason Cooper --- drivers/irqchip/irq-gic-common.c | 15 +++++++++------ drivers/irqchip/irq-gic.c | 25 +++++++++++++------------ include/linux/irqchip/arm-gic.h | 15 +++++++++++++++ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 60ac704d2090..61541ff24397 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -74,20 +74,22 @@ void __init gic_dist_config(void __iomem *base, int gic_irqs, * Set all global interrupts to be level triggered, active low. */ for (i = 32; i < gic_irqs; i += 16) - writel_relaxed(0, base + GIC_DIST_CONFIG + i / 4); + writel_relaxed(GICD_INT_ACTLOW_LVLTRIG, + base + GIC_DIST_CONFIG + i / 4); /* * Set priority on all global interrupts. */ for (i = 32; i < gic_irqs; i += 4) - writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i); + writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i); /* * Disable all interrupts. Leave the PPI and SGIs alone * as they are enabled by redistributor registers. */ for (i = 32; i < gic_irqs; i += 32) - writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i / 8); + writel_relaxed(GICD_INT_EN_CLR_X32, + base + GIC_DIST_ENABLE_CLEAR + i / 8); if (sync_access) sync_access(); @@ -101,14 +103,15 @@ void gic_cpu_config(void __iomem *base, void (*sync_access)(void)) * Deal with the banked PPI and SGI interrupts - disable all * PPI interrupts, ensure all SGI interrupts are enabled. */ - writel_relaxed(0xffff0000, base + GIC_DIST_ENABLE_CLEAR); - writel_relaxed(0x0000ffff, base + GIC_DIST_ENABLE_SET); + writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR); + writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET); /* * Set priority on PPI and SGI interrupts */ for (i = 0; i < 32; i += 4) - writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); + writel_relaxed(GICD_INT_DEF_PRI_X4, + base + GIC_DIST_PRI + i * 4 / 4); if (sync_access) sync_access(); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e606fe8..35847453cecb 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -298,8 +298,8 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK); raw_spin_unlock(&irq_controller_lock); - gic_irq = (status & 0x3ff); - if (gic_irq == 1023) + gic_irq = (status & GICC_IAR_INT_ID_MASK); + if (gic_irq == GICC_INT_SPURIOUS) goto out; cascade_irq = irq_find_mapping(chip_data->domain, gic_irq); @@ -360,7 +360,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic) unsigned int gic_irqs = gic->gic_irqs; void __iomem *base = gic_data_dist_base(gic); - writel_relaxed(0, base + GIC_DIST_CTRL); + writel_relaxed(GICD_DISABLE, base + GIC_DIST_CTRL); /* * Set all global interrupts to this CPU only. @@ -373,7 +373,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic) gic_dist_config(base, gic_irqs, NULL); - writel_relaxed(1, base + GIC_DIST_CTRL); + writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL); } static void gic_cpu_init(struct gic_chip_data *gic) @@ -400,8 +400,8 @@ static void gic_cpu_init(struct gic_chip_data *gic) gic_cpu_config(dist_base, NULL); - writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); - writel_relaxed(1, base + GIC_CPU_CTRL); + writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK); + writel_relaxed(GICC_ENABLE, base + GIC_CPU_CTRL); } void gic_cpu_if_down(void) @@ -467,14 +467,14 @@ static void gic_dist_restore(unsigned int gic_nr) if (!dist_base) return; - writel_relaxed(0, dist_base + GIC_DIST_CTRL); + writel_relaxed(GICD_DISABLE, dist_base + GIC_DIST_CTRL); for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++) writel_relaxed(gic_data[gic_nr].saved_spi_conf[i], dist_base + GIC_DIST_CONFIG + i * 4); for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++) - writel_relaxed(0xa0a0a0a0, + writel_relaxed(GICD_INT_DEF_PRI_X4, dist_base + GIC_DIST_PRI + i * 4); for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++) @@ -485,7 +485,7 @@ static void gic_dist_restore(unsigned int gic_nr) writel_relaxed(gic_data[gic_nr].saved_spi_enable[i], dist_base + GIC_DIST_ENABLE_SET + i * 4); - writel_relaxed(1, dist_base + GIC_DIST_CTRL); + writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL); } static void gic_cpu_save(unsigned int gic_nr) @@ -539,10 +539,11 @@ static void gic_cpu_restore(unsigned int gic_nr) writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4); for (i = 0; i < DIV_ROUND_UP(32, 4); i++) - writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4); + writel_relaxed(GICD_INT_DEF_PRI_X4, + dist_base + GIC_DIST_PRI + i * 4); - writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK); - writel_relaxed(1, cpu_base + GIC_CPU_CTRL); + writel_relaxed(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK); + writel_relaxed(GICC_ENABLE, cpu_base + GIC_CPU_CTRL); } static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 45e2d8c15bd2..5cb9d41af5be 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -21,7 +21,10 @@ #define GIC_CPU_ACTIVEPRIO 0xd0 #define GIC_CPU_IDENT 0xfc +#define GICC_ENABLE 0x1 +#define GICC_INT_PRI_THRESHOLD 0xf0 #define GICC_IAR_INT_ID_MASK 0x3ff +#define GICC_INT_SPURIOUS 1023 #define GIC_DIST_CTRL 0x000 #define GIC_DIST_CTR 0x004 @@ -39,6 +42,18 @@ #define GIC_DIST_SGI_PENDING_CLEAR 0xf10 #define GIC_DIST_SGI_PENDING_SET 0xf20 +#define GICD_ENABLE 0x1 +#define GICD_DISABLE 0x0 +#define GICD_INT_ACTLOW_LVLTRIG 0x0 +#define GICD_INT_EN_CLR_X32 0xffffffff +#define GICD_INT_EN_SET_SGI 0x0000ffff +#define GICD_INT_EN_CLR_PPI 0xffff0000 +#define GICD_INT_DEF_PRI 0xa0 +#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\ + (GICD_INT_DEF_PRI << 16) |\ + (GICD_INT_DEF_PRI << 8) |\ + GICD_INT_DEF_PRI) + #define GICH_HCR 0x0 #define GICH_VTR 0x4 #define GICH_VMCR 0x8 -- GitLab From 3228950621d92f0f212378f95a6998ef3a1be0bb Mon Sep 17 00:00:00 2001 From: Feng Kan Date: Wed, 30 Jul 2014 14:56:59 -0700 Subject: [PATCH 0391/5088] irqchip: gic: Preserve gic V2 bypass bits in cpu ctrl register This change is made to preserve the GIC v2 bypass bits in the GIC_CPU_CTRL register (also known as the GICC_CTLR register in spec). This code will preserve all bits configured by the bootloader regarding v2 bypass group bits. In the X-Gene platform, the bypass functionality is not used and bypass bits should not be changed by the kernel gic code as it could lead to incorrect behavior. Signed-off-by: Feng Kan Reviewed-by: Vinayak Kale Reviewed-by: Anup Patel Link: https://lkml.kernel.org/r/1406757419-18729-3-git-send-email-fkan@apm.com Signed-off-by: Jason Cooper --- drivers/irqchip/irq-gic.c | 25 ++++++++++++++++++++++--- include/linux/irqchip/arm-gic.h | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 35847453cecb..2500f6ba29e1 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -353,6 +353,21 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic) return mask; } +static void gic_cpu_if_up(void) +{ + void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]); + u32 bypass = 0; + + /* + * Preserve bypass disable bits to be written back later + */ + bypass = readl(cpu_base + GIC_CPU_CTRL); + bypass &= GICC_DIS_BYPASS_MASK; + + writel_relaxed(bypass | GICC_ENABLE, cpu_base + GIC_CPU_CTRL); +} + + static void __init gic_dist_init(struct gic_chip_data *gic) { unsigned int i; @@ -401,13 +416,17 @@ static void gic_cpu_init(struct gic_chip_data *gic) gic_cpu_config(dist_base, NULL); writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK); - writel_relaxed(GICC_ENABLE, base + GIC_CPU_CTRL); + gic_cpu_if_up(); } void gic_cpu_if_down(void) { void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]); - writel_relaxed(0, cpu_base + GIC_CPU_CTRL); + u32 val = 0; + + val = readl(cpu_base + GIC_CPU_CTRL); + val &= ~GICC_ENABLE; + writel_relaxed(val, cpu_base + GIC_CPU_CTRL); } #ifdef CONFIG_CPU_PM @@ -543,7 +562,7 @@ static void gic_cpu_restore(unsigned int gic_nr) dist_base + GIC_DIST_PRI + i * 4); writel_relaxed(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK); - writel_relaxed(GICC_ENABLE, cpu_base + GIC_CPU_CTRL); + gic_cpu_if_up(); } static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 5cb9d41af5be..13eed92c7d24 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -25,6 +25,7 @@ #define GICC_INT_PRI_THRESHOLD 0xf0 #define GICC_IAR_INT_ID_MASK 0x3ff #define GICC_INT_SPURIOUS 1023 +#define GICC_DIS_BYPASS_MASK 0x1e0 #define GIC_DIST_CTRL 0x000 #define GIC_DIST_CTR 0x004 -- GitLab From 23e11811378259831777e8fdc8b9836faeaa72cd Mon Sep 17 00:00:00 2001 From: Vignesh Raman Date: Tue, 5 Aug 2014 18:39:41 +0530 Subject: [PATCH 0392/5088] dma: imx-sdma: use module_platform_driver for SDMA driver Currently there is no module_exit declared in SDMA driver, so that once sdma module is inserted, it's shown with permanent attribute by lsmod, and it can't be removed. Use module_platform_driver to register/unregister SDMA driver and modify SDMA's remove operation, to make SDMA driver possible to be removed. Signed-off-by: Jiada Wang Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index f7626e37d0b8..40e65a4df94d 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1603,6 +1603,8 @@ static int __init sdma_probe(struct platform_device *pdev) sdma->dma_device.dev->dma_parms = &sdma->dma_parms; dma_set_max_seg_size(sdma->dma_device.dev, 65535); + platform_set_drvdata(pdev, sdma); + ret = dma_async_device_register(&sdma->dma_device); if (ret) { dev_err(&pdev->dev, "unable to register\n"); @@ -1640,7 +1642,20 @@ static int __init sdma_probe(struct platform_device *pdev) static int sdma_remove(struct platform_device *pdev) { - return -EBUSY; + struct sdma_engine *sdma = platform_get_drvdata(pdev); + struct resource *iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int irq = platform_get_irq(pdev, 0); + + dma_async_device_unregister(&sdma->dma_device); + kfree(sdma->script_addrs); + free_irq(irq, sdma); + iounmap(sdma->regs); + release_mem_region(iores->start, resource_size(iores)); + kfree(sdma); + + platform_set_drvdata(pdev, NULL); + dev_info(&pdev->dev, "Removed...\n"); + return 0; } static struct platform_driver sdma_driver = { @@ -1650,13 +1665,10 @@ static struct platform_driver sdma_driver = { }, .id_table = sdma_devtypes, .remove = sdma_remove, + .probe = sdma_probe, }; -static int __init sdma_module_init(void) -{ - return platform_driver_probe(&sdma_driver, sdma_probe); -} -module_init(sdma_module_init); +module_platform_driver(sdma_driver); MODULE_AUTHOR("Sascha Hauer, Pengutronix "); MODULE_DESCRIPTION("i.MX SDMA driver"); -- GitLab From c12fe49726cfebacb47dca5f2bb544c38aa09e6d Mon Sep 17 00:00:00 2001 From: Vignesh Raman Date: Tue, 5 Aug 2014 18:39:42 +0530 Subject: [PATCH 0393/5088] dma: imx-sdma: Adding tasklet_kill() in sdma_remove function. Several dma drivers calls tasklet_kill() in remove function. This is done because all running tasklets should be killed on remove. This is missing in imx sdma driver, so adding tasklet_kill() in sdma_remove function. Signed-off-by: Vignesh Raman Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 40e65a4df94d..c615e88c118a 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1645,12 +1645,19 @@ static int sdma_remove(struct platform_device *pdev) struct sdma_engine *sdma = platform_get_drvdata(pdev); struct resource *iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); + int i; dma_async_device_unregister(&sdma->dma_device); kfree(sdma->script_addrs); free_irq(irq, sdma); iounmap(sdma->regs); release_mem_region(iores->start, resource_size(iores)); + /* Kill the tasklet */ + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + struct sdma_channel *sdmac = &sdma->channel[i]; + + tasklet_kill(&sdmac->tasklet); + } kfree(sdma); platform_set_drvdata(pdev, NULL); -- GitLab From cdec729765659adafba983d6b6760ad52c71d5d8 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 19 Aug 2014 12:49:34 +0800 Subject: [PATCH 0394/5088] ASoC: fsl: Fix building of imx-es8328 on PPC The imx-es8328 driver fails to build on PPC because it explicitly depends on SND_SOC_IMX_PCM_FIQ, which itself doesn't build on PPC. Instead, rely on the SND_SOC_FSL_SSI config option to pull in the necessary libraries. While we're at it, remove SND_SOC_FSL_UTILS, which also is not needed. Signed-off-by: Sean Cross Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 4698c01af684..3154f43b11ab 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -266,8 +266,6 @@ config SND_SOC_IMX_ES8328 select SND_SOC_IMX_PCM_DMA select SND_SOC_IMX_AUDMUX select SND_SOC_FSL_SSI - select SND_SOC_FSL_UTILS - select SND_SOC_IMX_PCM_FIQ help Say Y if you want to add support for the ES8328 audio codec connected via SSI/I2S over either SPI or I2C. -- GitLab From 4f37b504768c952b64bc9469a2d579c7597590f2 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 19 Aug 2014 10:51:04 +0400 Subject: [PATCH 0395/5088] libata: Use dev_name() for request_irq() to distinguish devices Use dev_name() instead of driver name for request_irq(). This will help to distinguish between multiple identical devices. Before: CPU0 5: 34425 clps711x-intc 5 pata_of_platform 6: 6778 clps711x-intc 6 pata_of_platform After: CPU0 5: 2182 clps711x-intc 5 20000000.ide 6: 11024 clps711x-intc 6 20100000.ide Signed-off-by: Alexander Shiyan Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index dbdc5d32343f..782d126cf191 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6227,7 +6227,7 @@ int ata_host_activate(struct ata_host *host, int irq, } rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags, - dev_driver_string(host->dev), host); + dev_name(host->dev), host); if (rc) return rc; -- GitLab From 81c7cfd1b22a0ee5e40efef72ec2cd17dbf12e6d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:18 +0200 Subject: [PATCH 0396/5088] ASoC: Move debugfs registration to the component level The debugfs registration is mostly identical between platforms and CODECs. This patches consolidates the two implementations at the component level. Unfortunately there are still a couple of CODEC specific debugfs files that are related to legacy ASoC IO that need to be registered. For this a new callback is added to the component struct that will be initialized when a CODEC is registered and will be used to register the CODEC specific files. Once there are no drivers left using legacy IO this can be removed again. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 20 +++++-- sound/soc/soc-core.c | 122 ++++++++++++++++++------------------------- 2 files changed, 67 insertions(+), 75 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index be6ecae247b0..0ab8b1e4a5d2 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -728,9 +728,24 @@ struct snd_soc_component { struct mutex io_mutex; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; +#endif + + /* + * DO NOT use any of the fields below in drivers, they are temporary and + * are going to be removed again soon. If you use them in driver code the + * driver will be marked as BROKEN when these fields are removed. + */ + /* Don't use these, use snd_soc_component_get_dapm() */ struct snd_soc_dapm_context dapm; struct snd_soc_dapm_context *dapm_ptr; + +#ifdef CONFIG_DEBUG_FS + void (*init_debugfs)(struct snd_soc_component *component); + const char *debugfs_prefix; +#endif }; /* SoC Audio Codec device */ @@ -766,7 +781,6 @@ struct snd_soc_codec { struct snd_soc_dapm_context dapm; #ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_codec_root; struct dentry *debugfs_reg; #endif }; @@ -879,10 +893,6 @@ struct snd_soc_platform { struct list_head list; struct snd_soc_component component; - -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_platform_root; -#endif }; struct snd_soc_dai_link { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d4bfd4a9076f..79371a77f324 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -270,79 +270,56 @@ static const struct file_operations codec_reg_fops = { .llseek = default_llseek, }; -static struct dentry *soc_debugfs_create_dir(struct dentry *parent, - const char *fmt, ...) +static void soc_init_component_debugfs(struct snd_soc_component *component) { - struct dentry *de; - va_list ap; - char *s; + if (component->debugfs_prefix) { + char *name; - va_start(ap, fmt); - s = kvasprintf(GFP_KERNEL, fmt, ap); - va_end(ap); + name = kasprintf(GFP_KERNEL, "%s:%s", + component->debugfs_prefix, component->name); + if (name) { + component->debugfs_root = debugfs_create_dir(name, + component->card->debugfs_card_root); + kfree(name); + } + } else { + component->debugfs_root = debugfs_create_dir(component->name, + component->card->debugfs_card_root); + } - if (!s) - return NULL; + if (!component->debugfs_root) { + dev_warn(component->dev, + "ASoC: Failed to create component debugfs directory\n"); + return; + } - de = debugfs_create_dir(s, parent); - kfree(s); + snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component), + component->debugfs_root); - return de; + if (component->init_debugfs) + component->init_debugfs(component); } -static void soc_init_codec_debugfs(struct snd_soc_codec *codec) +static void soc_cleanup_component_debugfs(struct snd_soc_component *component) { - struct dentry *debugfs_card_root = codec->component.card->debugfs_card_root; + debugfs_remove_recursive(component->debugfs_root); +} - codec->debugfs_codec_root = soc_debugfs_create_dir(debugfs_card_root, - "codec:%s", - codec->component.name); - if (!codec->debugfs_codec_root) { - dev_warn(codec->dev, - "ASoC: Failed to create codec debugfs directory\n"); - return; - } +static void soc_init_codec_debugfs(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root, + debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, &codec->cache_sync); - debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root, + debugfs_create_bool("cache_only", 0444, codec->component.debugfs_root, &codec->cache_only); codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, - codec->debugfs_codec_root, + codec->component.debugfs_root, codec, &codec_reg_fops); if (!codec->debugfs_reg) dev_warn(codec->dev, "ASoC: Failed to create codec register debugfs file\n"); - - snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); -} - -static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ - debugfs_remove_recursive(codec->debugfs_codec_root); -} - -static void soc_init_platform_debugfs(struct snd_soc_platform *platform) -{ - struct dentry *debugfs_card_root = platform->component.card->debugfs_card_root; - - platform->debugfs_platform_root = soc_debugfs_create_dir(debugfs_card_root, - "platform:%s", - platform->component.name); - if (!platform->debugfs_platform_root) { - dev_warn(platform->dev, - "ASoC: Failed to create platform debugfs directory\n"); - return; - } - - snd_soc_dapm_debugfs_init(&platform->component.dapm, - platform->debugfs_platform_root); -} - -static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) -{ - debugfs_remove_recursive(platform->debugfs_platform_root); } static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, @@ -474,19 +451,15 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) #else -static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ -} +#define soc_init_codec_debugfs NULL -static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) +static inline void soc_init_component_debugfs( + struct snd_soc_component *component) { } -static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform) -{ -} - -static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) +static inline void soc_cleanup_component_debugfs( + struct snd_soc_component *component) { } @@ -1026,7 +999,7 @@ static int soc_remove_platform(struct snd_soc_platform *platform) /* Make sure all DAPM widgets are freed */ snd_soc_dapm_free(&platform->component.dapm); - soc_cleanup_platform_debugfs(platform); + soc_cleanup_component_debugfs(&platform->component); platform->probed = 0; module_put(platform->dev->driver->owner); @@ -1046,7 +1019,7 @@ static void soc_remove_codec(struct snd_soc_codec *codec) /* Make sure all DAPM widgets are freed */ snd_soc_dapm_free(&codec->dapm); - soc_cleanup_codec_debugfs(codec); + soc_cleanup_component_debugfs(&codec->component); codec->probed = 0; list_del(&codec->card_list); module_put(codec->dev->driver->owner); @@ -1187,7 +1160,7 @@ static int soc_probe_codec(struct snd_soc_card *card, if (!try_module_get(codec->dev->driver->owner)) return -ENODEV; - soc_init_codec_debugfs(codec); + soc_init_component_debugfs(&codec->component); if (driver->dapm_widgets) { ret = snd_soc_dapm_new_controls(&codec->dapm, @@ -1242,7 +1215,7 @@ static int soc_probe_codec(struct snd_soc_card *card, return 0; err_probe: - soc_cleanup_codec_debugfs(codec); + soc_cleanup_component_debugfs(&codec->component); module_put(codec->dev->driver->owner); return ret; @@ -1262,7 +1235,7 @@ static int soc_probe_platform(struct snd_soc_card *card, if (!try_module_get(platform->dev->driver->owner)) return -ENODEV; - soc_init_platform_debugfs(platform); + soc_init_component_debugfs(&platform->component); if (driver->dapm_widgets) snd_soc_dapm_new_controls(&platform->component.dapm, @@ -1302,7 +1275,7 @@ static int soc_probe_platform(struct snd_soc_card *card, return 0; err_probe: - soc_cleanup_platform_debugfs(platform); + soc_cleanup_component_debugfs(&platform->component); module_put(platform->dev->driver->owner); return ret; @@ -4266,6 +4239,10 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, if (platform_drv->read) platform->component.read = snd_soc_platform_drv_read; +#ifdef CONFIG_DEBUG_FS + platform->component.debugfs_prefix = "platform"; +#endif + mutex_lock(&client_mutex); snd_soc_component_add_unlocked(&platform->component); list_add(&platform->list, &platform_list); @@ -4455,6 +4432,11 @@ int snd_soc_register_codec(struct device *dev, codec->component.val_bytes = codec_drv->reg_word_size; mutex_init(&codec->mutex); +#ifdef CONFIG_DEBUG_FS + codec->component.init_debugfs = soc_init_codec_debugfs; + codec->component.debugfs_prefix = "codec"; +#endif + if (!codec->component.write) { if (codec_drv->get_regmap) regmap = codec_drv->get_regmap(dev); -- GitLab From f1d45cc3ae96a6173129b2c164c216272faa5fc0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:19 +0200 Subject: [PATCH 0397/5088] ASoC: Consolidate platform and CODEC probe/remove The platform and CODEC probe and remove code is now largely identical. This patch consolidates it at the component level. The resulting code is slightly larger due to all the boiler plate code setting up the indirection for the table based control and DAPM registration. Once all drivers have been update to no longer use the snd_soc_codec_driver and snd_soc_platform_driver specific fields for this the indirection can be removed again. This patch contains two noteworthy hacks that are only meant to be temporary to be able to update drivers and the core in separate incremental patches. The first hack is related to that some DPCM platforms expect that the DAPM widgets for the DAIs of a snd_soc_component are created in the DAPM context of the snd_soc_platform that has the same parent device. For handling this the steal_sibling_dai_widgets attribute is introduced. It gets set for snd_soc_platforms that register DAPM elements. When creating the DAI widgets for a component this flag is checked and if it is found on one of the siblings the component will not create any DAI widgets in its own DAPM context. If the attribute is set on a platform it will look for siblings components and create DAI widgets for them in its own context. The fix for this will be to update the offending drivers to only register a single component rather than two. The second hack deals with the fact that the ASoC card suspend and resume code still needs a list of CODECs that have been registered for the card. To handle this the generic probe and remove path have a check to see if the component is CODEC and if yes add/remove it to the card's CODEC list. While it is possible to clean up the suspend/resume code to not need the CODEC list anymore this is a bit of a chicken and egg problem since it will become easier to clean up the suspend/resume code once there is a unified component layer. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 27 ++- sound/soc/soc-core.c | 335 +++++++++++++------------- sound/soc/soc-generic-dmaengine-pcm.c | 4 +- 3 files changed, 194 insertions(+), 172 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 0ab8b1e4a5d2..22543acfae4b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -697,6 +697,10 @@ struct snd_soc_component_driver { void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type, int subseq); int (*stream_event)(struct snd_soc_component *, int event); + + /* probe ordering - for components with runtime dependencies */ + int probe_order; + int remove_order; }; struct snd_soc_component { @@ -710,6 +714,7 @@ 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; @@ -742,6 +747,18 @@ struct snd_soc_component { struct snd_soc_dapm_context dapm; struct snd_soc_dapm_context *dapm_ptr; + const struct snd_kcontrol_new *controls; + unsigned int num_controls; + const struct snd_soc_dapm_widget *dapm_widgets; + unsigned int num_dapm_widgets; + const struct snd_soc_dapm_route *dapm_routes; + unsigned int num_dapm_routes; + bool steal_sibling_dai_widgets; + struct snd_soc_codec *codec; + + int (*probe)(struct snd_soc_component *); + void (*remove)(struct snd_soc_component *); + #ifdef CONFIG_DEBUG_FS void (*init_debugfs)(struct snd_soc_component *component); const char *debugfs_prefix; @@ -761,7 +778,6 @@ struct snd_soc_codec { struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ unsigned int cache_bypass:1; /* Suppress access to the cache */ unsigned int suspended:1; /* Codec is in suspend PM state */ - unsigned int probed:1; /* Codec has been probed */ unsigned int ac97_registered:1; /* Codec has been AC97 registered */ unsigned int ac97_created:1; /* Codec has been created by SoC */ unsigned int cache_init:1; /* codec cache has been initialized */ @@ -827,10 +843,6 @@ struct snd_soc_codec_driver { enum snd_soc_dapm_type, int); bool ignore_pmdown_time; /* Doesn't benefit from pmdown delay */ - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; }; /* SoC platform interface */ @@ -867,10 +879,6 @@ struct snd_soc_platform_driver { /* platform stream compress ops */ const struct snd_compr_ops *compr_ops; - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; - /* platform IO - used for platform DAPM */ unsigned int (*read)(struct snd_soc_platform *, unsigned int); int (*write)(struct snd_soc_platform *, unsigned int, unsigned int); @@ -888,7 +896,6 @@ struct snd_soc_platform { const struct snd_soc_platform_driver *driver; unsigned int suspended:1; /* platform is suspended */ - unsigned int probed:1; struct list_head list; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 79371a77f324..b833cc6fd86d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -985,44 +985,20 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) return 0; } -static int soc_remove_platform(struct snd_soc_platform *platform) +static void soc_remove_component(struct snd_soc_component *component) { - int ret; - - if (platform->driver->remove) { - ret = platform->driver->remove(platform); - if (ret < 0) - dev_err(platform->dev, "ASoC: failed to remove %d\n", - ret); - } - - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&platform->component.dapm); - - soc_cleanup_component_debugfs(&platform->component); - platform->probed = 0; - module_put(platform->dev->driver->owner); - - return 0; -} - -static void soc_remove_codec(struct snd_soc_codec *codec) -{ - int err; + /* This is a HACK and will be removed soon */ + if (component->codec) + list_del(&component->codec->card_list); - if (codec->driver->remove) { - err = codec->driver->remove(codec); - if (err < 0) - dev_err(codec->dev, "ASoC: failed to remove %d\n", err); - } + if (component->remove) + component->remove(component); - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&codec->dapm); + snd_soc_dapm_free(snd_soc_component_get_dapm(component)); - soc_cleanup_component_debugfs(&codec->component); - codec->probed = 0; - list_del(&codec->card_list); - module_put(codec->dev->driver->owner); + soc_cleanup_component_debugfs(component); + component->probed = 0; + module_put(component->dev->driver->owner); } static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) @@ -1086,25 +1062,24 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, int i; /* remove the platform */ - if (platform && platform->probed && - platform->driver->remove_order == order) { - soc_remove_platform(platform); - } + if (platform && platform->component.probed && + platform->component.driver->remove_order == order) + soc_remove_component(&platform->component); /* remove the CODEC-side CODEC */ for (i = 0; i < rtd->num_codecs; i++) { codec = rtd->codec_dais[i]->codec; - if (codec && codec->probed && - codec->driver->remove_order == order) - soc_remove_codec(codec); + if (codec && codec->component.probed && + codec->component.driver->remove_order == order) + soc_remove_component(&codec->component); } /* remove any CPU-side CODEC */ if (cpu_dai) { codec = cpu_dai->codec; - if (codec && codec->probed && - codec->driver->remove_order == order) - soc_remove_codec(codec); + if (codec && codec->component.probed && + codec->component.driver->remove_order == order) + soc_remove_component(&codec->component); } } @@ -1146,137 +1121,108 @@ static void soc_set_name_prefix(struct snd_soc_card *card, } } -static int soc_probe_codec(struct snd_soc_card *card, - struct snd_soc_codec *codec) +static int soc_probe_component(struct snd_soc_card *card, + struct snd_soc_component *component) { - int ret = 0; - const struct snd_soc_codec_driver *driver = codec->driver; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_component *dai_component, *component2; struct snd_soc_dai *dai; + int ret; - codec->component.card = card; - codec->dapm.card = card; - soc_set_name_prefix(card, &codec->component); + component->card = card; + dapm->card = card; + soc_set_name_prefix(card, component); - if (!try_module_get(codec->dev->driver->owner)) + if (!try_module_get(component->dev->driver->owner)) return -ENODEV; - soc_init_component_debugfs(&codec->component); + soc_init_component_debugfs(component); - if (driver->dapm_widgets) { - ret = snd_soc_dapm_new_controls(&codec->dapm, - driver->dapm_widgets, - driver->num_dapm_widgets); + if (component->dapm_widgets) { + ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets, + component->num_dapm_widgets); if (ret != 0) { - dev_err(codec->dev, + dev_err(component->dev, "Failed to create new controls %d\n", ret); goto err_probe; } } - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(dai, &codec->component.dai_list, list) { - ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); + /* + * This is rather ugly, but certain platforms expect that the DAPM + * widgets for the DAIs for components with the same parent device are + * created in the platforms DAPM context. Until that is fixed we need to + * keep this. + */ + if (component->steal_sibling_dai_widgets) { + dai_component = NULL; + list_for_each_entry(component2, &component_list, list) { + if (component == component2) + continue; - if (ret != 0) { - dev_err(codec->dev, - "Failed to create DAI widgets %d\n", ret); - goto err_probe; + if (component2->dev == component->dev && + !list_empty(&component2->dai_list)) { + dai_component = component2; + break; + } } - } - - codec->dapm.idle_bias_off = driver->idle_bias_off; - - if (driver->probe) { - ret = driver->probe(codec); - if (ret < 0) { - dev_err(codec->dev, - "ASoC: failed to probe CODEC %d\n", ret); - goto err_probe; + } else { + dai_component = component; + list_for_each_entry(component2, &component_list, list) { + if (component2->dev == component->dev && + component2->steal_sibling_dai_widgets) { + dai_component = NULL; + break; + } } - WARN(codec->dapm.idle_bias_off && - codec->dapm.bias_level != SND_SOC_BIAS_OFF, - "codec %s can not start from non-off bias with idle_bias_off==1\n", - codec->component.name); } - if (driver->controls) - snd_soc_add_codec_controls(codec, driver->controls, - driver->num_controls); - if (driver->dapm_routes) - snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, - driver->num_dapm_routes); - - /* mark codec as probed and add to card codec list */ - codec->probed = 1; - list_add(&codec->card_list, &card->codec_dev_list); - list_add(&codec->dapm.list, &card->dapm_list); - - return 0; - -err_probe: - soc_cleanup_component_debugfs(&codec->component); - module_put(codec->dev->driver->owner); - - return ret; -} - -static int soc_probe_platform(struct snd_soc_card *card, - struct snd_soc_platform *platform) -{ - int ret = 0; - const struct snd_soc_platform_driver *driver = platform->driver; - struct snd_soc_component *component; - struct snd_soc_dai *dai; - - platform->component.card = card; - platform->component.dapm.card = card; - - if (!try_module_get(platform->dev->driver->owner)) - return -ENODEV; - - soc_init_component_debugfs(&platform->component); - - if (driver->dapm_widgets) - snd_soc_dapm_new_controls(&platform->component.dapm, - driver->dapm_widgets, driver->num_dapm_widgets); - - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(component, &component_list, list) { - if (component->dev != platform->dev) - continue; - list_for_each_entry(dai, &component->dai_list, list) - snd_soc_dapm_new_dai_widgets(&platform->component.dapm, - dai); + if (dai_component) { + list_for_each_entry(dai, &dai_component->dai_list, list) { + snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(component->dev, + "Failed to create DAI widgets %d\n", + ret); + goto err_probe; + } + } } - platform->component.dapm.idle_bias_off = 1; - - if (driver->probe) { - ret = driver->probe(platform); + if (component->probe) { + ret = component->probe(component); if (ret < 0) { - dev_err(platform->dev, - "ASoC: failed to probe platform %d\n", ret); + dev_err(component->dev, + "ASoC: failed to probe component %d\n", ret); goto err_probe; } + + WARN(dapm->idle_bias_off && + dapm->bias_level != SND_SOC_BIAS_OFF, + "codec %s can not start from non-off bias with idle_bias_off==1\n", + component->name); } - if (driver->controls) - snd_soc_add_platform_controls(platform, driver->controls, - driver->num_controls); - if (driver->dapm_routes) - snd_soc_dapm_add_routes(&platform->component.dapm, - driver->dapm_routes, driver->num_dapm_routes); + if (component->controls) + snd_soc_add_component_controls(component, component->controls, + component->num_controls); + if (component->dapm_routes) + snd_soc_dapm_add_routes(dapm, component->dapm_routes, + component->num_dapm_routes); - /* mark platform as probed and add to card platform list */ - platform->probed = 1; - list_add(&platform->component.dapm.list, &card->dapm_list); + component->probed = 1; + list_add(&dapm->list, &card->dapm_list); + + /* This is a HACK and will be removed soon */ + if (component->codec) + list_add(&component->codec->card_list, &card->codec_dev_list); return 0; err_probe: - soc_cleanup_component_debugfs(&platform->component); - module_put(platform->dev->driver->owner); + soc_cleanup_component_debugfs(component); + module_put(component->dev->driver->owner); return ret; } @@ -1334,33 +1280,36 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; int i, ret; /* probe the CPU-side component, if it is a CODEC */ - if (cpu_dai->codec && - !cpu_dai->codec->probed && - cpu_dai->codec->driver->probe_order == order) { - ret = soc_probe_codec(card, cpu_dai->codec); - if (ret < 0) - return ret; + if (rtd->cpu_dai->codec) { + component = &rtd->cpu_dai->codec->component; + if (!component->probed && + component->driver->probe_order == order) { + ret = soc_probe_component(card, component); + if (ret < 0) + return ret; + } } /* probe the CODEC-side components */ for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->codec->probed && - rtd->codec_dais[i]->codec->driver->probe_order == order) { - ret = soc_probe_codec(card, rtd->codec_dais[i]->codec); + component = &rtd->codec_dais[i]->codec->component; + if (!component->probed && + component->driver->probe_order == order) { + ret = soc_probe_component(card, component); if (ret < 0) return ret; } } /* probe the platform */ - if (!platform->probed && - platform->driver->probe_order == order) { - ret = soc_probe_platform(card, platform); + if (!platform->component.probed && + platform->component.driver->probe_order == order) { + ret = soc_probe_component(card, &platform->component); if (ret < 0) return ret; } @@ -1647,12 +1596,12 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; int ret; - if (rtd->codec->probed) { + if (rtd->codec->component.probed) { dev_err(rtd->codec->dev, "ASoC: codec already probed\n"); return -EBUSY; } - ret = soc_probe_codec(card, rtd->codec); + ret = soc_probe_component(card, &rtd->codec->component); if (ret < 0) return ret; @@ -1681,8 +1630,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) rtd->dev_registered = 0; } - if (codec && codec->probed) - soc_remove_codec(codec); + if (codec && codec->component.probed) + soc_remove_component(&codec->component); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) @@ -4198,6 +4147,20 @@ void snd_soc_unregister_component(struct device *dev) } EXPORT_SYMBOL_GPL(snd_soc_unregister_component); +static int snd_soc_platform_drv_probe(struct snd_soc_component *component) +{ + struct snd_soc_platform *platform = snd_soc_component_to_platform(component); + + return platform->driver->probe(platform); +} + +static void snd_soc_platform_drv_remove(struct snd_soc_component *component) +{ + struct snd_soc_platform *platform = snd_soc_component_to_platform(component); + + platform->driver->remove(platform); +} + static int snd_soc_platform_drv_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) { @@ -4234,6 +4197,24 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->dev = dev; platform->driver = platform_drv; + if (platform_drv->controls) { + platform->component.controls = platform_drv->controls; + platform->component.num_controls = platform_drv->num_controls; + } + if (platform_drv->dapm_widgets) { + platform->component.dapm_widgets = platform_drv->dapm_widgets; + platform->component.num_dapm_widgets = platform_drv->num_dapm_widgets; + platform->component.steal_sibling_dai_widgets = true; + } + if (platform_drv->dapm_routes) { + platform->component.dapm_routes = platform_drv->dapm_routes; + platform->component.num_dapm_routes = platform_drv->num_dapm_routes; + } + + if (platform_drv->probe) + platform->component.probe = snd_soc_platform_drv_probe; + if (platform_drv->remove) + platform->component.remove = snd_soc_platform_drv_remove; if (platform_drv->write) platform->component.write = snd_soc_platform_drv_write; if (platform_drv->read) @@ -4363,6 +4344,20 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) stream->formats |= codec_format_map[i]; } +static int snd_soc_codec_drv_probe(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return codec->driver->probe(codec); +} + +static void snd_soc_codec_drv_remove(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + codec->driver->remove(codec); +} + static int snd_soc_codec_drv_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) { @@ -4411,12 +4406,30 @@ int snd_soc_register_codec(struct device *dev, return -ENOMEM; codec->component.dapm_ptr = &codec->dapm; + codec->component.codec = codec; ret = snd_soc_component_initialize(&codec->component, &codec_drv->component_driver, dev); if (ret) goto err_free; + if (codec_drv->controls) { + codec->component.controls = codec_drv->controls; + codec->component.num_controls = codec_drv->num_controls; + } + if (codec_drv->dapm_widgets) { + codec->component.dapm_widgets = codec_drv->dapm_widgets; + codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets; + } + if (codec_drv->dapm_routes) { + codec->component.dapm_routes = codec_drv->dapm_routes; + codec->component.num_dapm_routes = codec_drv->num_dapm_routes; + } + + if (codec_drv->probe) + codec->component.probe = snd_soc_codec_drv_probe; + if (codec_drv->remove) + codec->component.remove = snd_soc_codec_drv_remove; if (codec_drv->write) codec->component.write = snd_soc_codec_drv_write; if (codec_drv->read) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6307f85e871b..b329b84bc5af 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -336,10 +336,12 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = { }; static const struct snd_soc_platform_driver dmaengine_pcm_platform = { + .component_driver = { + .probe_order = SND_SOC_COMP_ORDER_LATE, + }, .ops = &dmaengine_pcm_ops, .pcm_new = dmaengine_pcm_new, .pcm_free = dmaengine_pcm_free, - .probe_order = SND_SOC_COMP_ORDER_LATE, }; static const char * const dmaengine_pcm_dma_channel_names[] = { -- GitLab From 93c3ce76ccced3a8718149e8734ccaa931e9a1f1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:20 +0200 Subject: [PATCH 0398/5088] ASoC: Make rtd->codec optional There are some place in the ASoC core that expect rtd->codec to be non NULL (mainly CODEC specific sysfs files). With componentization going forward rtd->codec might be NULL in some cases. This patch prepares the core for this by not registering CODEC specific sysfs files if rtd->codec is NULL. sysfs file removal does not need to be conditionalized as it handles the removal of non-existing files just fine. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b833cc6fd86d..1c705c28389c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1261,17 +1261,21 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, } rtd->dev_registered = 1; - /* add DAPM sysfs entries for this codec */ - ret = snd_soc_dapm_sys_add(rtd->dev); - if (ret < 0) - dev_err(rtd->dev, - "ASoC: failed to add codec dapm sysfs entries: %d\n", ret); + if (rtd->codec) { + /* add DAPM sysfs entries for this codec */ + ret = snd_soc_dapm_sys_add(rtd->dev); + if (ret < 0) + dev_err(rtd->dev, + "ASoC: failed to add codec dapm sysfs entries: %d\n", + ret); - /* add codec sysfs entries */ - ret = device_create_file(rtd->dev, &dev_attr_codec_reg); - if (ret < 0) - dev_err(rtd->dev, - "ASoC: failed to add codec sysfs files: %d\n", ret); + /* add codec sysfs entries */ + ret = device_create_file(rtd->dev, &dev_attr_codec_reg); + if (ret < 0) + dev_err(rtd->dev, + "ASoC: failed to add codec sysfs files: %d\n", + ret); + } return 0; } -- GitLab From 61aca5646b736a794d40de29a197144db3f0c5ba Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:21 +0200 Subject: [PATCH 0399/5088] ASoC: Add component level probe/remove support Now that we have a unified probe and remove path make sure to call them for all components. soc_{probe,remove}_component are responsible for setting up the DAPM context for the component, initialize the component prefix, manage the debugfs entries as well as do the registration of table based controls and DAPM elements. They also call the component drivers probe and remove callbacks. This patch makes these things available for generic snd_soc_component drivers rather than only having them for snd_soc_codec and snd_soc_platform drivers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 11 +++++++++++ sound/soc/soc-core.c | 42 ++++++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 22543acfae4b..4a223a895f00 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -690,6 +690,17 @@ struct snd_soc_compr_ops { struct snd_soc_component_driver { const char *name; + /* Default control and setup, added after probe() is run */ + const struct snd_kcontrol_new *controls; + unsigned int num_controls; + const struct snd_soc_dapm_widget *dapm_widgets; + unsigned int num_dapm_widgets; + const struct snd_soc_dapm_route *dapm_routes; + unsigned int num_dapm_routes; + + int (*probe)(struct snd_soc_component *); + void (*remove)(struct snd_soc_component *); + /* DT */ int (*of_xlate_dai_name)(struct snd_soc_component *component, struct of_phandle_args *args, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1c705c28389c..08fd85e8c751 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1058,7 +1058,7 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; - struct snd_soc_codec *codec; + struct snd_soc_component *component; int i; /* remove the platform */ @@ -1068,18 +1068,17 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, /* remove the CODEC-side CODEC */ for (i = 0; i < rtd->num_codecs; i++) { - codec = rtd->codec_dais[i]->codec; - if (codec && codec->component.probed && - codec->component.driver->remove_order == order) - soc_remove_component(&codec->component); + component = rtd->codec_dais[i]->component; + if (component->probed && + component->driver->remove_order == order) + soc_remove_component(component); } /* remove any CPU-side CODEC */ if (cpu_dai) { - codec = cpu_dai->codec; - if (codec && codec->component.probed && - codec->component.driver->remove_order == order) - soc_remove_component(&codec->component); + if (cpu_dai->component->probed && + cpu_dai->component->driver->remove_order == order) + soc_remove_component(cpu_dai->component); } } @@ -1289,19 +1288,17 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, int i, ret; /* probe the CPU-side component, if it is a CODEC */ - if (rtd->cpu_dai->codec) { - component = &rtd->cpu_dai->codec->component; - if (!component->probed && - component->driver->probe_order == order) { - ret = soc_probe_component(card, component); - if (ret < 0) - return ret; - } + component = rtd->cpu_dai->component; + if (!component->probed && + component->driver->probe_order == order) { + ret = soc_probe_component(card, component); + if (ret < 0) + return ret; } /* probe the CODEC-side components */ for (i = 0; i < rtd->num_codecs; i++) { - component = &rtd->codec_dais[i]->codec->component; + component = rtd->codec_dais[i]->component; if (!component->probed && component->driver->probe_order == order) { ret = soc_probe_component(card, component); @@ -4042,6 +4039,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->dev = dev; component->driver = driver; + component->probe = component->driver->probe; + component->remove = component->driver->remove; if (!component->dapm_ptr) component->dapm_ptr = &component->dapm; @@ -4055,6 +4054,13 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, if (driver->stream_event) dapm->stream_event = snd_soc_component_stream_event; + component->controls = driver->controls; + component->num_controls = driver->num_controls; + component->dapm_widgets = driver->dapm_widgets; + component->num_dapm_widgets = driver->num_dapm_widgets; + component->dapm_routes = driver->dapm_routes; + component->num_dapm_routes = driver->num_dapm_routes; + INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex); -- GitLab From 65d9361f0cb50a20641802ee3075145d72e4409c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:22 +0200 Subject: [PATCH 0400/5088] ASoC: Move AUX dev support to the component level This patch makes it possible to register arbitrary components as a AUX dev for a card. This was previously only possible for CODEC components. With componentization having made it possible for components to have DAPM contexts and controls there is no reason why AUX devs should be artificially limited to snd_soc_codec devices. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + sound/soc/soc-core.c | 48 +++++++++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 4a223a895f00..fbc2ad840244 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1140,6 +1140,7 @@ struct snd_soc_pcm_runtime { struct snd_soc_platform *platform; struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai; + struct snd_soc_component *component; /* Only valid for AUX dev rtds */ struct snd_soc_dai **codec_dais; unsigned int num_codecs; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 08fd85e8c751..08c04f4c7e62 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -860,6 +860,23 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); static const struct snd_soc_dai_ops null_dai_ops = { }; +static struct snd_soc_component *soc_find_component( + const struct device_node *of_node, const char *name) +{ + struct snd_soc_component *component; + + list_for_each_entry(component, &component_list, list) { + if (of_node) { + if (component->dev->of_node == of_node) + return component; + } else if (strcmp(component->name, name) == 0) { + return component; + } + } + + return NULL; +} + static struct snd_soc_codec *soc_find_codec( const struct device_node *codec_of_node, const char *codec_name) @@ -1577,17 +1594,24 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; - const char *codecname = aux_dev->codec_name; + const char *name = aux_dev->codec_name; - rtd->codec = soc_find_codec(aux_dev->codec_of_node, codecname); - if (!rtd->codec) { + rtd->component = soc_find_component(aux_dev->codec_of_node, name); + if (!rtd->component) { if (aux_dev->codec_of_node) - codecname = of_node_full_name(aux_dev->codec_of_node); + name = of_node_full_name(aux_dev->codec_of_node); - dev_err(card->dev, "ASoC: %s not registered\n", codecname); + dev_err(card->dev, "ASoC: %s not registered\n", name); return -EPROBE_DEFER; } + /* + * Some places still reference rtd->codec, so we have to keep that + * initialized if the component is a CODEC. Once all those references + * have been removed, this code can be removed as well. + */ + rtd->codec = rtd->component->codec; + return 0; } @@ -1597,18 +1621,18 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; int ret; - if (rtd->codec->component.probed) { - dev_err(rtd->codec->dev, "ASoC: codec already probed\n"); + if (rtd->component->probed) { + dev_err(rtd->dev, "ASoC: codec already probed\n"); return -EBUSY; } - ret = soc_probe_component(card, &rtd->codec->component); + ret = soc_probe_component(card, rtd->component); if (ret < 0) return ret; /* do machine specific initialization */ if (aux_dev->init) { - ret = aux_dev->init(&rtd->codec->dapm); + ret = aux_dev->init(snd_soc_component_get_dapm(rtd->component)); if (ret < 0) { dev_err(card->dev, "ASoC: failed to init %s: %d\n", aux_dev->name, ret); @@ -1622,7 +1646,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) static void soc_remove_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_component *component = rtd->component; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -1631,8 +1655,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) rtd->dev_registered = 0; } - if (codec && codec->component.probed) - soc_remove_component(&codec->component); + if (component && component->probed) + soc_remove_component(component); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) -- GitLab From 57bf772687700e206c760ba2e4097f78bde97887 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:23 +0200 Subject: [PATCH 0401/5088] ASoC: Pass component instead of DAPM context to AUX dev init callback Given that the component is the containing structure it makes more sense to pass the component rather than the DAPM context to the AUX dev init callback. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- sound/soc/samsung/speyside.c | 6 ++++-- sound/soc/soc-core.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index fbc2ad840244..3a0031e1f9b4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1022,7 +1022,7 @@ struct snd_soc_aux_dev { const struct device_node *codec_of_node; /* codec/machine specific init - e.g. add machine controls */ - int (*init)(struct snd_soc_dapm_context *dapm); + int (*init)(struct snd_soc_component *component); }; /* SoC card */ diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 9902efcb8ea1..a05482651aae 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -228,10 +228,12 @@ static struct snd_soc_dai_link speyside_dai[] = { }, }; -static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm) +static int speyside_wm9081_init(struct snd_soc_component *component) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + /* At any time the WM9081 is active it will have this clock */ - return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0, + return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0, MCLK_AUDIO_RATE, 0); } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 08c04f4c7e62..4393bc33d3af 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1632,7 +1632,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) /* do machine specific initialization */ if (aux_dev->init) { - ret = aux_dev->init(snd_soc_component_get_dapm(rtd->component)); + ret = aux_dev->init(rtd->component); if (ret < 0) { dev_err(card->dev, "ASoC: failed to init %s: %d\n", aux_dev->name, ret); -- GitLab From 70090bbb8b7d7da7a6f64969b43a61c493c560ff Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:24 +0200 Subject: [PATCH 0402/5088] ASoC: Move component->probed check into soc_{remove,probe}_component() Having the check in a centralized place makes the code a bit cleaner and shorter. Note: There is a slight semantic change in this patch. soc_probe_aux_dev() will no longer return -EBUSY if the AUX dev has already been probed before. This is fine though since it will simply do nothing in that case and return success. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4393bc33d3af..2fbfbfca48dc 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1004,6 +1004,9 @@ 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) + return; + /* This is a HACK and will be removed soon */ if (component->codec) list_del(&component->codec->card_list); @@ -1079,22 +1082,19 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, int i; /* remove the platform */ - if (platform && platform->component.probed && - platform->component.driver->remove_order == order) + if (platform && platform->component.driver->remove_order == order) soc_remove_component(&platform->component); /* remove the CODEC-side CODEC */ for (i = 0; i < rtd->num_codecs; i++) { component = rtd->codec_dais[i]->component; - if (component->probed && - component->driver->remove_order == order) + if (component->driver->remove_order == order) soc_remove_component(component); } /* remove any CPU-side CODEC */ if (cpu_dai) { - if (cpu_dai->component->probed && - cpu_dai->component->driver->remove_order == order) + if (cpu_dai->component->driver->remove_order == order) soc_remove_component(cpu_dai->component); } } @@ -1145,6 +1145,9 @@ static int soc_probe_component(struct snd_soc_card *card, struct snd_soc_dai *dai; int ret; + if (component->probed) + return 0; + component->card = card; dapm->card = card; soc_set_name_prefix(card, component); @@ -1306,8 +1309,7 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, /* probe the CPU-side component, if it is a CODEC */ component = rtd->cpu_dai->component; - if (!component->probed && - component->driver->probe_order == order) { + if (component->driver->probe_order == order) { ret = soc_probe_component(card, component); if (ret < 0) return ret; @@ -1316,8 +1318,7 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, /* probe the CODEC-side components */ for (i = 0; i < rtd->num_codecs; i++) { component = rtd->codec_dais[i]->component; - if (!component->probed && - component->driver->probe_order == order) { + if (component->driver->probe_order == order) { ret = soc_probe_component(card, component); if (ret < 0) return ret; @@ -1325,8 +1326,7 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, } /* probe the platform */ - if (!platform->component.probed && - platform->component.driver->probe_order == order) { + if (platform->component.driver->probe_order == order) { ret = soc_probe_component(card, &platform->component); if (ret < 0) return ret; @@ -1621,11 +1621,6 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; int ret; - if (rtd->component->probed) { - dev_err(rtd->dev, "ASoC: codec already probed\n"); - return -EBUSY; - } - ret = soc_probe_component(card, rtd->component); if (ret < 0) return ret; -- GitLab From ffbd7dd72bd3ad9bcae9190788c858e57f1e8e4e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:25 +0200 Subject: [PATCH 0403/5088] ASoC: Cleanup DAI module reference counting Currently when a DAI has no CODEC associated to it the reference on the module containing the DAI driver is increased when the DAI is probed and decrease when the DAI is removed. For DAIs with CODECs the module reference count was already incremented when the CODEC is probed. Now that all components have their module reference count incremented when they are probed and all DAIs do have a component it is possible to remove the module reference counting on DAI probe and removal. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2fbfbfca48dc..4dc2876c06de 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1067,8 +1067,6 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) cpu_dai->name, err); } cpu_dai->probed = 0; - if (!cpu_dai->codec) - module_put(cpu_dai->dev->driver->owner); } } @@ -1422,18 +1420,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) /* probe the cpu_dai */ if (!cpu_dai->probed && cpu_dai->driver->probe_order == order) { - if (!cpu_dai->codec) { - if (!try_module_get(cpu_dai->dev->driver->owner)) - return -ENODEV; - } - if (cpu_dai->driver->probe) { ret = cpu_dai->driver->probe(cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, "ASoC: failed to probe CPU DAI %s: %d\n", cpu_dai->name, ret); - module_put(cpu_dai->dev->driver->owner); return ret; } } -- GitLab From e60cd14f0bf6c004cd7032a24a036ba32d56e08a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:26 +0200 Subject: [PATCH 0404/5088] ASoC: Consolidate CPU and CODEC DAI removal CPU and CODEC DAI works exactly the same way. There is already a helper function for CODEC DAI removal, use that one as well for CPU DAI removal. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4dc2876c06de..5f6f97874ca2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1021,28 +1021,27 @@ static void soc_remove_component(struct snd_soc_component *component) module_put(component->dev->driver->owner); } -static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) +static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (codec_dai && codec_dai->probed && - codec_dai->driver->remove_order == order) { - if (codec_dai->driver->remove) { - err = codec_dai->driver->remove(codec_dai); + if (dai && dai->probed && + dai->driver->remove_order == order) { + if (dai->driver->remove) { + err = dai->driver->remove(dai); if (err < 0) - dev_err(codec_dai->dev, + dev_err(dai->dev, "ASoC: failed to remove %s: %d\n", - codec_dai->name, err); + dai->name, err); } - codec_dai->probed = 0; + dai->probed = 0; } } static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int i, err; + int i; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -1054,20 +1053,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) /* remove the CODEC DAI */ for (i = 0; i < rtd->num_codecs; i++) - soc_remove_codec_dai(rtd->codec_dais[i], order); + soc_remove_dai(rtd->codec_dais[i], order); - /* remove the cpu_dai */ - if (cpu_dai && cpu_dai->probed && - cpu_dai->driver->remove_order == order) { - if (cpu_dai->driver->remove) { - err = cpu_dai->driver->remove(cpu_dai); - if (err < 0) - dev_err(cpu_dai->dev, - "ASoC: failed to remove %s: %d\n", - cpu_dai->name, err); - } - cpu_dai->probed = 0; - } + soc_remove_dai(rtd->cpu_dai, order); } static void soc_remove_link_components(struct snd_soc_card *card, int num, -- GitLab From 14621c7e5e72200ec021a7580121130ce7f2ff22 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:27 +0200 Subject: [PATCH 0405/5088] ASoC: Consolidate CPU and CODEC DAI lookup The lookup of CPU and CODEC DAIs is fairly similar and can easily be consolidated into a single helper function. There are two main differences in the current implementation of the CPU and CODEC DAI lookup: 1) CPU DAIs can be looked up by the DAI name alone and do not necessarily require a component name/of_node. 2) The CODEC DAI search only considers DAIs from CODEC components. For 1) the new helper function will allow to lookup DAIs without providing a component name or of_node, but since snd_soc_register_card() already rejects CODEC DAI link components without neither a of_node or a name we'll never get into the situation where we try to lookup a CODEC DAI without a name/of_node. For 2) the new helper function just always considers all components. Componentization is now at a point where it is possible to register a CODEC as a snd_soc_component rather than a snd_soc_codec, by considering DAIs from all components it is possible to use such a CODEC in a DAI link. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 72 ++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 53 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5f6f97874ca2..140f43f91635 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -877,35 +877,23 @@ static struct snd_soc_component *soc_find_component( return NULL; } -static struct snd_soc_codec *soc_find_codec( - const struct device_node *codec_of_node, - const char *codec_name) +static struct snd_soc_dai *snd_soc_find_dai( + const struct snd_soc_dai_link_component *dlc) { - struct snd_soc_codec *codec; + struct snd_soc_component *component; + struct snd_soc_dai *dai; - list_for_each_entry(codec, &codec_list, list) { - if (codec_of_node) { - if (codec->dev->of_node != codec_of_node) - continue; - } else { - if (strcmp(codec->component.name, codec_name)) + /* Find CPU DAI from registered DAIs*/ + list_for_each_entry(component, &component_list, list) { + if (dlc->of_node && component->dev->of_node != dlc->of_node) + continue; + if (dlc->name && strcmp(dev_name(component->dev), dlc->name)) + continue; + list_for_each_entry(dai, &component->dai_list, list) { + if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)) continue; - } - - return codec; - } - - return NULL; -} - -static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec, - const char *codec_dai_name) -{ - struct snd_soc_dai *codec_dai; - list_for_each_entry(codec_dai, &codec->component.dai_list, list) { - if (!strcmp(codec_dai->name, codec_dai_name)) { - return codec_dai; + return dai; } } @@ -916,33 +904,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_component *component; struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_platform *platform; - struct snd_soc_dai *cpu_dai; const char *platform_name; int i; dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); - /* Find CPU DAI from registered DAIs*/ - list_for_each_entry(component, &component_list, list) { - if (dai_link->cpu_of_node && - component->dev->of_node != dai_link->cpu_of_node) - continue; - if (dai_link->cpu_name && - strcmp(dev_name(component->dev), dai_link->cpu_name)) - continue; - list_for_each_entry(cpu_dai, &component->dai_list, list) { - if (dai_link->cpu_dai_name && - strcmp(cpu_dai->name, dai_link->cpu_dai_name)) - continue; - - rtd->cpu_dai = cpu_dai; - } - } - + cpu_dai_component.name = dai_link->cpu_name; + cpu_dai_component.of_node = dai_link->cpu_of_node; + cpu_dai_component.dai_name = dai_link->cpu_dai_name; + rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); if (!rtd->cpu_dai) { dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", dai_link->cpu_dai_name); @@ -953,15 +927,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) /* Find CODEC from registered CODECs */ for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_codec *codec; - codec = soc_find_codec(codecs[i].of_node, codecs[i].name); - if (!codec) { - dev_err(card->dev, "ASoC: CODEC %s not registered\n", - codecs[i].name); - return -EPROBE_DEFER; - } - - codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name); + codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", codecs[i].dai_name); -- GitLab From 886f5692253de1a9509f5cb708432b2157afb57c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:28 +0200 Subject: [PATCH 0406/5088] ASoC: Automatically initialize regmap for all components So far regmap is only automatically initialized for CODECs. Now that we have the infrastructure in place to let components have DAPM widgets and controls that want to use the generic regmap based IO also make sure to automatically initialize regmap for all components. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 3 --- sound/soc/soc-core.c | 35 +++++++++++++++++------------------ sound/soc/soc-io.c | 28 ---------------------------- 3 files changed, 17 insertions(+), 49 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 3a0031e1f9b4..8ebee30311e3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1289,9 +1289,6 @@ void snd_soc_component_async_complete(struct snd_soc_component *component); int snd_soc_component_test_bits(struct snd_soc_component *component, unsigned int reg, unsigned int mask, unsigned int value); -int snd_soc_component_init_io(struct snd_soc_component *component, - struct regmap *regmap); - /* device driver data */ static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 140f43f91635..96f286643ca1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4032,8 +4032,23 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, return 0; } +static void snd_soc_component_init_regmap(struct snd_soc_component *component) +{ + if (!component->regmap) + component->regmap = dev_get_regmap(component->dev, NULL); + if (component->regmap) { + int val_bytes = regmap_get_val_bytes(component->regmap); + /* Errors are legitimate for non-integer byte multiples */ + if (val_bytes > 0) + component->val_bytes = val_bytes; + } +} + static void snd_soc_component_add_unlocked(struct snd_soc_component *component) { + if (!component->write && !component->read) + snd_soc_component_init_regmap(component); + list_add(&component->list, &component_list); } @@ -4371,7 +4386,6 @@ int snd_soc_register_codec(struct device *dev, { struct snd_soc_codec *codec; struct snd_soc_dai *dai; - struct regmap *regmap; int ret, i; dev_dbg(dev, "codec register %s\n", dev_name(dev)); @@ -4425,23 +4439,8 @@ int snd_soc_register_codec(struct device *dev, codec->component.debugfs_prefix = "codec"; #endif - if (!codec->component.write) { - if (codec_drv->get_regmap) - regmap = codec_drv->get_regmap(dev); - else - regmap = dev_get_regmap(dev, NULL); - - if (regmap) { - ret = snd_soc_component_init_io(&codec->component, - regmap); - if (ret) { - dev_err(codec->dev, - "Failed to set cache I/O:%d\n", - ret); - goto err_cleanup; - } - } - } + if (codec_drv->get_regmap) + codec->component.regmap = codec_drv->get_regmap(dev); for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 7767fbd73eb7..9b3939049cef 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -271,31 +271,3 @@ int snd_soc_platform_write(struct snd_soc_platform *platform, return snd_soc_component_write(&platform->component, reg, val); } EXPORT_SYMBOL_GPL(snd_soc_platform_write); - -/** - * snd_soc_component_init_io() - Initialize regmap IO - * - * @component: component to initialize - * @regmap: regmap instance to use for IO operations - * - * Return: 0 on success, a negative error code otherwise - */ -int snd_soc_component_init_io(struct snd_soc_component *component, - struct regmap *regmap) -{ - int ret; - - if (!regmap) - return -EINVAL; - - ret = regmap_get_val_bytes(regmap); - /* Errors are legitimate for non-integer byte - * multiples */ - if (ret > 0) - component->val_bytes = ret; - - component->regmap = regmap; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_component_init_io); -- GitLab From 75af7c081982d76cef0daf26e96b5d1e8cb9d631 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:29 +0200 Subject: [PATCH 0407/5088] ASoC: Remove support for legacy snd_soc_platform IO There were never any actual users of this in upstream and by we have with regmap a replacement in place, which should be used by new drivers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 3 --- sound/soc/soc-core.c | 22 ---------------------- 2 files changed, 25 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 8ebee30311e3..edbb0d72ab38 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -890,9 +890,6 @@ struct snd_soc_platform_driver { /* platform stream compress ops */ const struct snd_compr_ops *compr_ops; - /* platform IO - used for platform DAPM */ - unsigned int (*read)(struct snd_soc_platform *, unsigned int); - int (*write)(struct snd_soc_platform *, unsigned int, unsigned int); int (*bespoke_trigger)(struct snd_pcm_substream *, int); }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 96f286643ca1..2d7a9ecbb0e3 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4151,24 +4151,6 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component) platform->driver->remove(platform); } -static int snd_soc_platform_drv_write(struct snd_soc_component *component, - unsigned int reg, unsigned int val) -{ - struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - - return platform->driver->write(platform, reg, val); -} - -static int snd_soc_platform_drv_read(struct snd_soc_component *component, - unsigned int reg, unsigned int *val) -{ - struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - - *val = platform->driver->read(platform, reg); - - return 0; -} - /** * snd_soc_add_platform - Add a platform to the ASoC core * @dev: The parent device for the platform @@ -4205,10 +4187,6 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->component.probe = snd_soc_platform_drv_probe; if (platform_drv->remove) platform->component.remove = snd_soc_platform_drv_remove; - if (platform_drv->write) - platform->component.write = snd_soc_platform_drv_write; - if (platform_drv->read) - platform->component.read = snd_soc_platform_drv_read; #ifdef CONFIG_DEBUG_FS platform->component.debugfs_prefix = "platform"; -- GitLab From c5599b87a8317738a541d8893cb327df5d04b007 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:30 +0200 Subject: [PATCH 0408/5088] ASoC: Replace list_empty(&card->codec_dev_list) with !card->instantiated With componentization we no longer necessarily need a snd_soc_codec struct for a card. Instead of checking if the card's CODEC list is empty just use card->instantiated to check if the card has been instantiated yet. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2d7a9ecbb0e3..c36983a133fa 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -552,10 +552,8 @@ int snd_soc_suspend(struct device *dev) struct snd_soc_codec *codec; int i, j; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (list_empty(&card->codec_dev_list)) + /* If the card is not initialized yet there is nothing to do */ + if (!card->instantiated) return 0; /* Due to the resume being scheduled into a workqueue we could @@ -808,10 +806,8 @@ int snd_soc_resume(struct device *dev) struct snd_soc_card *card = dev_get_drvdata(dev); int i, ac97_control = 0; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (list_empty(&card->codec_dev_list)) + /* If the card is not initialized yet there is nothing to do */ + if (!card->instantiated) return 0; /* activate pins from sleep state */ -- GitLab From 38c6e4bb67760db1392b9c5ee0082af07c0db20d Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 19 Aug 2014 17:36:41 +0800 Subject: [PATCH 0409/5088] ASoC: fsl-asoc-card: move 'config SND_SOC_FSL_ASOC_CARD' to 'if SND_IMX_SOC' Build kernel with SND_SOC_FSL_ASOC_CARD=m && SND_SOC_FSL_{SSI,SAI,ESAI}=y leads the following error: sound/built-in.o: In function `fsl_sai_probe': >> fsl_sai.c:(.text+0x5f662): undefined reference to `imx_pcm_dma_init' sound/built-in.o: In function `fsl_esai_probe': >> fsl_esai.c:(.text+0x6044b): undefined reference to `imx_pcm_dma_init' The config SND_SOC_FSL_ASOC_CARD is for IMX SOC, So move it under condition of 'if SND_IMX_SOC'. Reported-by: kbuild test robot Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 3154f43b11ab..7c1da8ede975 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -59,23 +59,6 @@ config SND_SOC_FSL_ESAI config SND_SOC_FSL_UTILS tristate -config SND_SOC_FSL_ASOC_CARD - tristate "Generic ASoC Sound Card with ASRC support" - depends on OF && I2C - select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_PCM_DMA - select SND_SOC_FSL_ESAI - select SND_SOC_FSL_SAI - select SND_SOC_FSL_SSI - select SND_SOC_CS42XX8_I2C - select SND_SOC_SGTL5000 - select SND_SOC_WM8962 - help - ALSA SoC Audio support with ASRC feature for Freescale SoCs that have - ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888 - and SGTL5000. - Say Y if you want to add support for Freescale Generic ASoC Sound Card. - config SND_SOC_IMX_PCM_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM @@ -298,6 +281,23 @@ config SND_SOC_IMX_MC13783 select SND_SOC_MC13783 select SND_SOC_IMX_PCM_DMA +config SND_SOC_FSL_ASOC_CARD + tristate "Generic ASoC Sound Card with ASRC support" + depends on OF && I2C + select SND_SOC_IMX_AUDMUX + select SND_SOC_IMX_PCM_DMA + select SND_SOC_FSL_ESAI + select SND_SOC_FSL_SAI + select SND_SOC_FSL_SSI + select SND_SOC_CS42XX8_I2C + select SND_SOC_SGTL5000 + select SND_SOC_WM8962 + help + ALSA SoC Audio support with ASRC feature for Freescale SoCs that have + ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888 + and SGTL5000. + Say Y if you want to add support for Freescale Generic ASoC Sound Card. + endif # SND_IMX_SOC endmenu -- GitLab From 5d0ecb0e7dd53e61e034bac8508d7601b04e679d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 17:48:06 +0200 Subject: [PATCH 0410/5088] ASoC: sh: Don't opencode DMAengine API calls Use the proper wrapper functions instead of directly calling the DMAengine callback functions. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/sh/siu_pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index 488f9becb44f..32eb6da2d2bd 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -139,7 +139,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info, desc->callback = siu_dma_tx_complete; desc->callback_param = siu_stream; - cookie = desc->tx_submit(desc); + cookie = dmaengine_submit(desc); if (cookie < 0) { dev_err(dev, "Failed to submit a dma transfer\n"); return cookie; @@ -189,7 +189,7 @@ static int siu_pcm_rd_set(struct siu_port *port_info, desc->callback = siu_dma_tx_complete; desc->callback_param = siu_stream; - cookie = desc->tx_submit(desc); + cookie = dmaengine_submit(desc); if (cookie < 0) { dev_err(dev, "Failed to submit dma descriptor\n"); return cookie; -- GitLab From ff495d3a8ea4d46d237096e6521b24b7ba612e53 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 17:48:07 +0200 Subject: [PATCH 0411/5088] ASoC: txx9: Don't opencode DMAengine API calls Use the proper wrapper functions instead of directly calling the DMAengine callback functions. Also add the missing include to linux/dmaengine.h. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/txx9/txx9aclc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index f0829de28708..cd71fd889d8b 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -137,7 +138,7 @@ txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr) } desc->callback = txx9aclc_dma_complete; desc->callback_param = dmadata; - desc->tx_submit(desc); + dmaengine_submit(desc); return desc; } @@ -160,7 +161,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) void __iomem *base = drvdata->base; spin_unlock_irqrestore(&dmadata->dma_lock, flags); - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); /* first time */ for (i = 0; i < NR_DMA_CHAIN; i++) { desc = txx9aclc_dma_submit(dmadata, @@ -169,7 +170,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) return; } dmadata->dmacount = NR_DMA_CHAIN; - chan->device->device_issue_pending(chan); + dma_async_issue_pending(chan); spin_lock_irqsave(&dmadata->dma_lock, flags); __raw_writel(ctlbit, base + ACCTLEN); dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags; @@ -188,7 +189,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) dmadata->frag_count * dmadata->frag_bytes); if (!desc) return; - chan->device->device_issue_pending(chan); + dma_async_issue_pending(chan); spin_lock_irqsave(&dmadata->dma_lock, flags); dmadata->frag_count++; @@ -266,7 +267,7 @@ static int txx9aclc_pcm_close(struct snd_pcm_substream *substream) struct dma_chan *chan = dmadata->dma_chan; dmadata->frag_count = -1; - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); return 0; } @@ -398,8 +399,7 @@ static int txx9aclc_pcm_remove(struct snd_soc_platform *platform) struct dma_chan *chan = dmadata->dma_chan; if (chan) { dmadata->frag_count = -1; - chan->device->device_control(chan, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); dma_release_channel(chan); } dev->dmadata[i].dma_chan = NULL; -- GitLab From ddc643630f5deb1995d191719086b64873c67a44 Mon Sep 17 00:00:00 2001 From: Srikanth Thokala Date: Mon, 28 Jul 2014 17:47:48 +0530 Subject: [PATCH 0412/5088] dma: Add Xilinx AXI DMA DT Binding Documentation Device-tree binding documentation of Xilinx DMA Engine Signed-off-by: Srikanth Thokala Acked-by: Arnd Bergmann Signed-off-by: Vinod Koul --- .../bindings/dma/xilinx/xilinx_dma.txt | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt new file mode 100644 index 000000000000..2291c4098730 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt @@ -0,0 +1,65 @@ +Xilinx AXI DMA engine, it does transfers between memory and AXI4 stream +target devices. It can be configured to have one channel or two channels. +If configured as two channels, one is to transmit to the device and another +is to receive from the device. + +Required properties: +- compatible: Should be "xlnx,axi-dma-1.00.a" +- #dma-cells: Should be <1>, see "dmas" property below +- reg: Should contain DMA registers location and length. +- dma-channel child node: Should have atleast one channel and can have upto + two channels per device. This node specifies the properties of each + DMA channel (see child node properties below). + +Optional properties: +- xlnx,include-sg: Tells whether configured for Scatter-mode in + the hardware. + +Required child node properties: +- compatible: It should be either "xlnx,axi-dma-mm2s-channel" or + "xlnx,axi-dma-s2mm-channel". +- interrupts: Should contain per channel DMA interrupts. +- xlnx,datawidth: Should contain the stream data width, take values + {32,64...1024}. + +Option child node properties: +- xlnx,include-dre: Tells whether hardware is configured for Data + Realignment Engine. + +Example: +++++++++ + +axi_dma_0: axidma@40400000 { + compatible = "xlnx,axi-dma-1.00.a"; + #dma_cells = <1>; + reg = < 0x40400000 0x10000 >; + dma-channel@40400000 { + compatible = "xlnx,axi-dma-mm2s-channel"; + interrupts = < 0 59 4 >; + xlnx,datawidth = <0x40>; + } ; + dma-channel@40400030 { + compatible = "xlnx,axi-dma-s2mm-channel"; + interrupts = < 0 58 4 >; + xlnx,datawidth = <0x40>; + } ; +} ; + + +* DMA client + +Required properties: +- dmas: a list of <[DMA device phandle] [Channel ID]> pairs, + where Channel ID is '0' for write/tx and '1' for read/rx + channel. +- dma-names: a list of DMA channel names, one per "dmas" entry + +Example: +++++++++ + +dmatest_0: dmatest@0 { + compatible ="xlnx,axi-dma-test-1.00.a"; + dmas = <&axi_dma_0 0 + &axi_dma_0 1>; + dma-names = "dma0", "dma1"; +} ; -- GitLab From 29a4bb1431035560b4be3fc5917c5ab8b8141204 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 13 Aug 2014 13:57:42 +0200 Subject: [PATCH 0413/5088] dma: xilinx: Remove .owner field for driver There is no need to init .owner field. Based on the patch from Peter Griffin "mmc: remove .owner field for drivers using module_platform_driver" This patch removes the superflous .owner field for drivers which use the module_platform_driver API, as this is overriden in platform_driver_register anyway." Signed-off-by: Michal Simek Reviewed-by: Levente Kurusa Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_vdma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c index 42a13e8d4607..a6e64767186e 100644 --- a/drivers/dma/xilinx/xilinx_vdma.c +++ b/drivers/dma/xilinx/xilinx_vdma.c @@ -1365,7 +1365,6 @@ static const struct of_device_id xilinx_vdma_of_ids[] = { static struct platform_driver xilinx_vdma_driver = { .driver = { .name = "xilinx-vdma", - .owner = THIS_MODULE, .of_match_table = xilinx_vdma_of_ids, }, .probe = xilinx_vdma_probe, -- GitLab From 5828c60826e9422169b3711aa58a583242864cc8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 31 Jul 2014 18:36:20 +0300 Subject: [PATCH 0414/5088] mtd: ndfc: silence an array underflow static checker warning We check "cs" for array overflows but we don't check for underflows and it upsets the static checkers. Signed-off-by: Dan Carpenter Signed-off-by: Brian Norris --- drivers/mtd/nand/ndfc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 69eaba690a99..253a644da76a 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -203,7 +203,8 @@ static int ndfc_probe(struct platform_device *ofdev) struct ndfc_controller *ndfc; const __be32 *reg; u32 ccr; - int err, len, cs; + u32 cs; + int err, len; /* Read the reg property to get the chip select */ reg = of_get_property(ofdev->dev.of_node, "reg", &len); -- GitLab From 9b6e5172e363b0c35a6be4d3197f3bcdc789292e Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Thu, 31 Jul 2014 16:31:16 +0200 Subject: [PATCH 0415/5088] mtd: use NULL instead of 0 for an address Use NULL instead of 0 when returning an address. This fixes a sparse warning. Signed-off-by: Martin Kepplinger Signed-off-by: Brian Norris --- drivers/mtd/maps/pcmciamtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index a3cfad392ed6..af747af5eee9 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -89,7 +89,7 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) if (!pcmcia_dev_present(dev->p_dev)) { pr_debug("device removed\n"); - return 0; + return NULL; } offset = to & ~(dev->win_size-1); -- GitLab From 796fe3648a13b311f5b9a125e2d2532a2ce7c78a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Poggi?= Date: Tue, 29 Jul 2014 15:27:27 +0200 Subject: [PATCH 0416/5088] mtd: atmel_nand: increase chip_delay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some nand with 8k page size like Micron MT29F32G08ABAAAWP need more than 20us. Signed-off-by: Raphaël Poggi Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index e321c564ff05..77bd877d8f28 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -2099,7 +2099,7 @@ static int atmel_nand_probe(struct platform_device *pdev) } nand_chip->ecc.mode = host->board.ecc_mode; - nand_chip->chip_delay = 20; /* 20us command delay time */ + nand_chip->chip_delay = 40; /* 40us command delay time */ if (host->board.bus_width_16) /* 16-bit bus width */ nand_chip->options |= NAND_BUSWIDTH_16; -- GitLab From a35571058ec8e7c82dceea90cdecead51674f963 Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Tue, 22 Jul 2014 17:24:18 +0800 Subject: [PATCH 0417/5088] mtd: atmel_nand: add pmecc support for 512, 1k, 4k, 8k page size PMECC can support 512, 1k, 2k, 4k, 8k page size. The driver currently only support 2k page size nand flash. So this patch add support to 512, 1k, 4k and 8k page size nand flash. Signed-off-by: Josh Wu Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 77bd877d8f28..e4d57ffef07e 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1174,7 +1174,17 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, /* set ECC page size and oob layout */ switch (mtd->writesize) { + case 512: + case 1024: case 2048: + case 4096: + case 8192: + if (sector_size > mtd->writesize) { + dev_err(host->dev, "pmecc sector size is bigger than the page size!\n"); + err_no = -EINVAL; + goto err; + } + host->pmecc_degree = (sector_size == 512) ? PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; @@ -1201,13 +1211,9 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, nand_chip->ecc.layout = &atmel_pmecc_oobinfo; break; - case 512: - case 1024: - case 4096: - /* TODO */ + default: dev_warn(host->dev, "Unsupported page size for PMECC, use Software ECC\n"); - default: /* page size not handled by HW ECC */ /* switching back to soft ECC */ nand_chip->ecc.mode = NAND_ECC_SOFT; -- GitLab From 7b7d8982f0169d5ac67c6c2877449fb7f6968cac Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 27 Jul 2014 14:31:53 -0700 Subject: [PATCH 0418/5088] mtd: fix linux/mtd/nand.h kernel-doc warning Fix kernel-doc warning in : Warning(..//include/linux/mtd/nand.h:795): No description found for parameter 'ecc' Signed-off-by: Randy Dunlap Cc: David Woodhouse Cc: Brian Norris Cc: linux-mtd@lists.infradead.org Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 3083c53e0270..b7c11991cb09 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -766,6 +766,7 @@ struct nand_chip { * @options: stores various chip bit options * @id_len: The valid length of the @id. * @oobsize: OOB size + * @ecc: ECC correctability and step information from the datasheet. * @ecc.strength_ds: The ECC correctability from the datasheet, same as the * @ecc_strength_ds in nand_chip{}. * @ecc.step_ds: The ECC step required by the @ecc.strength_ds, same as the -- GitLab From f2fabe16b819cdead86fb38c8ab88a0d9c308293 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Sun, 27 Jul 2014 23:56:08 +0200 Subject: [PATCH 0419/5088] mtd: spi-nor: add support for Micron M25PX80 This commit adds the support in the spi-nor driver of the Micron M25PX80 flash, a 8 Mbit SPI flash from Micron. Signed-off-by: Thomas Petazzoni 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 b5ad6bebf5e7..4dc0c8662265 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -611,6 +611,7 @@ const struct spi_device_id spi_nor_ids[] = { { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, + { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, -- GitLab From 8fb7b9309c41407801958138db978eb38fd80c01 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 28 Jul 2014 21:19:55 +0800 Subject: [PATCH 0420/5088] mtd: atmel_nand: remove redundant dev_err call There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index e4d57ffef07e..0abc965caedf 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1148,7 +1148,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, host->ecc = devm_ioremap_resource(&pdev->dev, regs); if (IS_ERR(host->ecc)) { - dev_err(host->dev, "ioremap failed\n"); err_no = PTR_ERR(host->ecc); goto err; } @@ -1156,8 +1155,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2); host->pmerrloc_base = devm_ioremap_resource(&pdev->dev, regs_pmerr); if (IS_ERR(host->pmerrloc_base)) { - dev_err(host->dev, - "Can not get I/O resource for PMECC ERRLOC controller!\n"); err_no = PTR_ERR(host->pmerrloc_base); goto err; } @@ -1165,7 +1162,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); if (IS_ERR(host->pmecc_rom_base)) { - dev_err(host->dev, "Can not get I/O resource for ROM!\n"); err_no = PTR_ERR(host->pmecc_rom_base); goto err; } @@ -1536,10 +1532,8 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev, } host->ecc = devm_ioremap_resource(&pdev->dev, regs); - if (IS_ERR(host->ecc)) { - dev_err(host->dev, "ioremap failed\n"); + if (IS_ERR(host->ecc)) return PTR_ERR(host->ecc); - } /* ECC is calculated for the whole page (1 step) */ nand_chip->ecc.size = mtd->writesize; @@ -2046,7 +2040,6 @@ static int atmel_nand_probe(struct platform_device *pdev) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->io_base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(host->io_base)) { - dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n"); res = PTR_ERR(host->io_base); goto err_nand_ioremap; } -- GitLab From 2902330e7ac16d5962f114d92bb17631e9cb49e9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 11 Jul 2014 11:14:05 +0900 Subject: [PATCH 0421/5088] mtd: denali: avoid using a magic number MAP10 command with '0x2000' data sets up a read-ahead/write access. Signed-off-by: Masahiro Yamada Signed-off-by: Brian Norris --- drivers/mtd/nand/denali.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 0b071a3136a2..da0fcc224739 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -74,6 +74,7 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." #define SPARE_ACCESS 0x41 #define MAIN_ACCESS 0x42 #define MAIN_SPARE_ACCESS 0x43 +#define PIPELINE_ACCESS 0x2000 #define DENALI_READ 0 #define DENALI_WRITE 0x100 @@ -765,7 +766,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, iowrite32(cmd, denali->flash_mem); } else { index_addr(denali, (uint32_t)cmd, - 0x2000 | op | page_count); + PIPELINE_ACCESS | op | page_count); /* wait for command to be accepted * can always use status0 bit as the -- GitLab From 6f3c0f163103fb225c77b73ca17fc4ecea308103 Mon Sep 17 00:00:00 2001 From: Samarth Parikh Date: Wed, 16 Jul 2014 16:14:37 +0530 Subject: [PATCH 0422/5088] mtd: Fixed checkpatch seq_printf warnings Fixed checkpatch warnings: "WARNING: Prefer seq_puts to seq_printf" This patch is created with reference to the ongoing lkml thread https://lkml.org/lkml/2014/7/15/646 where Andrew Morton wrote: " - puts is presumably faster - puts doesn't go rogue if you accidentally pass it a "%". - this patch would actually make compiled object files few bytes smaller. Perhaps because seq_printf() is a varargs function, forcing the caller to pass args on the stack instead of in registers. " Signed-off-by: Samarth Parikh Signed-off-by: Brian Norris --- drivers/mtd/devices/docg3.c | 26 +++++++++++++------------- drivers/mtd/mtdswap.c | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 91a169c44b39..21cc4b66feaa 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1697,16 +1697,16 @@ static int dbg_asicmode_show(struct seq_file *s, void *p) switch (mode) { case DOC_ASICMODE_RESET: - pos += seq_printf(s, "reset"); + pos += seq_puts(s, "reset"); break; case DOC_ASICMODE_NORMAL: - pos += seq_printf(s, "normal"); + pos += seq_puts(s, "normal"); break; case DOC_ASICMODE_POWERDOWN: - pos += seq_printf(s, "powerdown"); + pos += seq_puts(s, "powerdown"); break; } - pos += seq_printf(s, ")\n"); + pos += seq_puts(s, ")\n"); return pos; } DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show); @@ -1745,22 +1745,22 @@ static int dbg_protection_show(struct seq_file *s, void *p) pos += seq_printf(s, "Protection = 0x%02x (", protect); if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK) - pos += seq_printf(s, "FOUNDRY_OTP_LOCK,"); + pos += seq_puts(s, "FOUNDRY_OTP_LOCK,"); if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK) - pos += seq_printf(s, "CUSTOMER_OTP_LOCK,"); + pos += seq_puts(s, "CUSTOMER_OTP_LOCK,"); if (protect & DOC_PROTECT_LOCK_INPUT) - pos += seq_printf(s, "LOCK_INPUT,"); + pos += seq_puts(s, "LOCK_INPUT,"); if (protect & DOC_PROTECT_STICKY_LOCK) - pos += seq_printf(s, "STICKY_LOCK,"); + pos += seq_puts(s, "STICKY_LOCK,"); if (protect & DOC_PROTECT_PROTECTION_ENABLED) - pos += seq_printf(s, "PROTECTION ON,"); + pos += seq_puts(s, "PROTECTION ON,"); if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK) - pos += seq_printf(s, "IPL_DOWNLOAD_LOCK,"); + pos += seq_puts(s, "IPL_DOWNLOAD_LOCK,"); if (protect & DOC_PROTECT_PROTECTION_ERROR) - pos += seq_printf(s, "PROTECT_ERR,"); + pos += seq_puts(s, "PROTECT_ERR,"); else - pos += seq_printf(s, "NO_PROTECT_ERR"); - pos += seq_printf(s, ")\n"); + pos += seq_puts(s, "NO_PROTECT_ERR"); + pos += seq_puts(s, ")\n"); pos += seq_printf(s, "DPS0 = 0x%02x : " "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 8b33b26eb12b..0ec96cd5dc78 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -1287,7 +1287,7 @@ static int mtdswap_show(struct seq_file *s, void *data) seq_printf(s, "total erasures: %lu\n", sum); - seq_printf(s, "\n"); + seq_puts(s, "\n"); seq_printf(s, "mtdswap_readsect count: %llu\n", d->sect_read_count); seq_printf(s, "mtdswap_writesect count: %llu\n", d->sect_write_count); @@ -1296,7 +1296,7 @@ static int mtdswap_show(struct seq_file *s, void *data) seq_printf(s, "mtd write count: %llu\n", d->mtd_write_count); seq_printf(s, "discarded pages count: %llu\n", d->discard_page_count); - seq_printf(s, "\n"); + seq_puts(s, "\n"); seq_printf(s, "total pages: %u\n", pages); seq_printf(s, "pages mapped: %u\n", mapped); -- GitLab From 57d3a9a89a0645f3597561e214f8d6852a2c56b4 Mon Sep 17 00:00:00 2001 From: White Ding Date: Thu, 24 Jul 2014 00:10:45 +0800 Subject: [PATCH 0423/5088] mtd: nand: fix nand_lock/unlock() function Do nand reset before write protect check. If we want to check the WP# low or high through STATUS READ and check bit 7, we must reset the device, other operation (eg.erase/program a locked block) can also clear the bit 7 of status register. As we know the status register can be refreshed, if we do some operation to trigger it, for example if we do erase/program operation to one block that is locked, then READ STATUS, the bit 7 of READ STATUS will be 0 indicate the device in write protect, then if we do erase/program operation to another block that is unlocked, the bit 7 of READ STATUS will be 1 indicate the device is not write protect. Suppose we checked the bit 7 of READ STATUS is 0 then judge the WP# is low (write protect), but in this case the WP# maybe high if we do erase/program operation to a locked block, so we must reset the device if we want to check the WP# low or high through STATUS READ and check bit 7. Signed-off-by: White Ding Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d8cdf06343fb..1a27c2da29ff 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -982,6 +982,15 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) chip->select_chip(mtd, chipnr); + /* + * Reset the chip. + * If we want to check the WP through READ STATUS and check the bit 7 + * we must reset the chip + * some operation can also clear the bit 7 of status register + * eg. erase/program a locked block + */ + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + /* Check, if it is write protected */ if (nand_check_wp(mtd)) { pr_debug("%s: device is write protected!\n", @@ -1032,6 +1041,15 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) chip->select_chip(mtd, chipnr); + /* + * Reset the chip. + * If we want to check the WP through READ STATUS and check the bit 7 + * we must reset the chip + * some operation can also clear the bit 7 of status register + * eg. erase/program a locked block + */ + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + /* Check, if it is write protected */ if (nand_check_wp(mtd)) { pr_debug("%s: device is write protected!\n", -- GitLab From 36c6a7ac74044b8025488c018279115bb3c32eb0 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:06:19 -0700 Subject: [PATCH 0424/5088] mtd: cfi_cmdset_0002: allow retry/timeout loop to exit The variable 'retries' is never modified, so if the reset operation never is going to complete, we'll get stuck in an infinite loop. It looks like the intention was to decrement 'retries' on every loop. Untested. Caught by Coverity. Signed-off-by: Brian Norris --- drivers/mtd/chips/cfi_cmdset_0002.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 5a4bfe33112a..6da141af9cba 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -2029,6 +2029,8 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip, udelay(1); } + + retries--; } /* the chip never became ready */ -- GitLab From 0c2b4e21444d0e274e91fc7db85caddb30988853 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:06:27 -0700 Subject: [PATCH 0425/5088] mtd: correct upper bounds check for mtd_*() APIs When checking the upper boundary (i.e., whether an address is higher than the maximum size of the MTD), we should be doing an inclusive check (greater or equal). For instance, an address of 16MB (0x1000000) on a 16MB device is invalid. The strengthening of this bounds check is redundant for those which already have a address+length check and ensure that the length is non-zero, but let's just fix them all, for completeness. Signed-off-by: Brian Norris --- drivers/mtd/mtdcore.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index e4831b4159db..c1015173f2d9 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -778,7 +778,7 @@ EXPORT_SYMBOL_GPL(__put_mtd_device); */ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) { - if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr) + if (instr->addr >= mtd->size || instr->len > mtd->size - instr->addr) return -EINVAL; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; @@ -804,7 +804,7 @@ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, *phys = 0; if (!mtd->_point) return -EOPNOTSUPP; - if (from < 0 || from > mtd->size || len > mtd->size - from) + if (from < 0 || from >= mtd->size || len > mtd->size - from) return -EINVAL; if (!len) return 0; @@ -817,7 +817,7 @@ int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { if (!mtd->_point) return -EOPNOTSUPP; - if (from < 0 || from > mtd->size || len > mtd->size - from) + if (from < 0 || from >= mtd->size || len > mtd->size - from) return -EINVAL; if (!len) return 0; @@ -835,7 +835,7 @@ unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len, { if (!mtd->_get_unmapped_area) return -EOPNOTSUPP; - if (offset > mtd->size || len > mtd->size - offset) + if (offset >= mtd->size || len > mtd->size - offset) return -EINVAL; return mtd->_get_unmapped_area(mtd, len, offset, flags); } @@ -846,7 +846,7 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, { int ret_code; *retlen = 0; - if (from < 0 || from > mtd->size || len > mtd->size - from) + if (from < 0 || from >= mtd->size || len > mtd->size - from) return -EINVAL; if (!len) return 0; @@ -869,7 +869,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { *retlen = 0; - if (to < 0 || to > mtd->size || len > mtd->size - to) + if (to < 0 || to >= mtd->size || len > mtd->size - to) return -EINVAL; if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE)) return -EROFS; @@ -892,7 +892,7 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, *retlen = 0; if (!mtd->_panic_write) return -EOPNOTSUPP; - if (to < 0 || to > mtd->size || len > mtd->size - to) + if (to < 0 || to >= mtd->size || len > mtd->size - to) return -EINVAL; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; @@ -1011,7 +1011,7 @@ int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { if (!mtd->_lock) return -EOPNOTSUPP; - if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) + if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs) return -EINVAL; if (!len) return 0; @@ -1023,7 +1023,7 @@ int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { if (!mtd->_unlock) return -EOPNOTSUPP; - if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) + if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs) return -EINVAL; if (!len) return 0; @@ -1035,7 +1035,7 @@ int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) { if (!mtd->_is_locked) return -EOPNOTSUPP; - if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) + if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs) return -EINVAL; if (!len) return 0; @@ -1045,7 +1045,7 @@ EXPORT_SYMBOL_GPL(mtd_is_locked); int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs) { - if (ofs < 0 || ofs > mtd->size) + if (ofs < 0 || ofs >= mtd->size) return -EINVAL; if (!mtd->_block_isreserved) return 0; @@ -1055,7 +1055,7 @@ EXPORT_SYMBOL_GPL(mtd_block_isreserved); int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) { - if (ofs < 0 || ofs > mtd->size) + if (ofs < 0 || ofs >= mtd->size) return -EINVAL; if (!mtd->_block_isbad) return 0; @@ -1067,7 +1067,7 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) { if (!mtd->_block_markbad) return -EOPNOTSUPP; - if (ofs < 0 || ofs > mtd->size) + if (ofs < 0 || ofs >= mtd->size) return -EINVAL; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; -- GitLab From f7f0d358f5f2f1133b5a14337028ddab848cd74e Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:06:39 -0700 Subject: [PATCH 0426/5088] mtd: sm_ftl: initialize error code There is one theoretical case that could fall through to using an uninitialized value as the return code. Let's give it a value of 0. Untested. Caught by Coverity. Signed-off-by: Brian Norris --- drivers/mtd/sm_ftl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index cf49c22673b9..c23184a47fc4 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -1058,7 +1058,7 @@ static int sm_write(struct mtd_blktrans_dev *dev, { struct sm_ftl *ftl = dev->priv; struct ftl_zone *zone; - int error, zone_num, block, boffset; + int error = 0, zone_num, block, boffset; BUG_ON(ftl->readonly); sm_break_offset(ftl, sec_no << 9, &zone_num, &block, &boffset); -- GitLab From 5e47212831ac565993d21ebd36216d98f2b58f30 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:06:47 -0700 Subject: [PATCH 0427/5088] mtd: remove dead non-char logic MTD used to allow compiling out character device support. This was dropped in the following commit, but some of the accompanying logic was never dropped: commit 660685d9d1b4730f0b5ca97fa95f272f99c63bce Author: Artem Bityutskiy Date: Thu Mar 14 13:27:40 2013 +0200 mtd: merge mtdchar module with mtdcore The weird logic was flagged by Coverity. Signed-off-by: Brian Norris Cc: Artem Bityutskiy --- drivers/mtd/mtdcore.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c1015173f2d9..4c611871d7e6 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -105,12 +105,11 @@ static LIST_HEAD(mtd_notifiers); */ static void mtd_release(struct device *dev) { - struct mtd_info __maybe_unused *mtd = dev_get_drvdata(dev); + struct mtd_info *mtd = dev_get_drvdata(dev); dev_t index = MTD_DEVT(mtd->index); - /* remove /dev/mtdXro node if needed */ - if (index) - device_destroy(&mtd_class, index + 1); + /* remove /dev/mtdXro node */ + device_destroy(&mtd_class, index + 1); } static int mtd_cls_suspend(struct device *dev, pm_message_t state) @@ -442,10 +441,8 @@ int add_mtd_device(struct mtd_info *mtd) if (device_register(&mtd->dev) != 0) goto fail_added; - if (MTD_DEVT(i)) - device_create(&mtd_class, mtd->dev.parent, - MTD_DEVT(i) + 1, - NULL, "mtd%dro", i); + device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL, + "mtd%dro", i); pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name); /* No need to get a refcount on the module containing -- GitLab From 8c3f3f1d7941bcb25590b784f84accd7dcb44ba3 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:02 -0700 Subject: [PATCH 0428/5088] mtd: mtdswap: fix integer overflow Caught by Coverity. Signed-off-by: Brian Norris --- drivers/mtd/mtdswap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 0ec96cd5dc78..48cf6f98df44 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -1474,7 +1474,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) } eblocks = mtd_div_by_eb(use_size, mtd); - use_size = eblocks * mtd->erasesize; + use_size = (uint64_t)eblocks * mtd->erasesize; bad_blocks = mtdswap_badblocks(mtd, use_size); eavailable = eblocks - bad_blocks; -- GitLab From 1001ff7a4f64f3f4264e69d3ed70ff428f627e01 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:12 -0700 Subject: [PATCH 0429/5088] mtd: tests: fix integer overflow issues These multiplications are done with 32-bit arithmetic, then converted to 64-bit. We should widen the integers first to prevent overflow. This could be a problem for large (>4GB) MTD's. Detected by Coverity. Signed-off-by: Brian Norris Cc: Akinobu Mita --- drivers/mtd/tests/mtd_test.c | 4 ++-- drivers/mtd/tests/nandbiterrs.c | 2 +- drivers/mtd/tests/oobtest.c | 8 ++++---- drivers/mtd/tests/pagetest.c | 4 ++-- drivers/mtd/tests/readtest.c | 2 +- drivers/mtd/tests/speedtest.c | 14 +++++++------- drivers/mtd/tests/subpagetest.c | 10 +++++----- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/mtd/tests/mtd_test.c b/drivers/mtd/tests/mtd_test.c index 111ee46a7428..34736bbcc07b 100644 --- a/drivers/mtd/tests/mtd_test.c +++ b/drivers/mtd/tests/mtd_test.c @@ -10,7 +10,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) { int err; struct erase_info ei; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; memset(&ei, 0, sizeof(struct erase_info)); ei.mtd = mtd; @@ -33,7 +33,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum) { int ret; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; ret = mtd_block_isbad(mtd, addr); if (ret) diff --git a/drivers/mtd/tests/nandbiterrs.c b/drivers/mtd/tests/nandbiterrs.c index 6f976159611f..273f7e553954 100644 --- a/drivers/mtd/tests/nandbiterrs.c +++ b/drivers/mtd/tests/nandbiterrs.c @@ -364,7 +364,7 @@ static int __init mtd_nandbiterrs_init(void) pr_info("Device uses %d subpages of %d bytes\n", subcount, subsize); - offset = page_offset * mtd->writesize; + offset = (loff_t)page_offset * mtd->writesize; eraseblock = mtd_div_by_eb(offset, mtd); pr_info("Using page=%u, offset=%llu, eraseblock=%u\n", diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index f19ab1acde1f..dc4f9602b97e 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -120,7 +120,7 @@ static int verify_eraseblock(int ebnum) int i; struct mtd_oob_ops ops; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { @@ -214,7 +214,7 @@ static int verify_eraseblock_in_one_go(int ebnum) { struct mtd_oob_ops ops; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; size_t len = mtd->ecclayout->oobavail * pgcnt; prandom_bytes_state(&rnd_state, writebuf, len); @@ -568,7 +568,7 @@ static int __init mtd_oobtest_init(void) size_t sz = mtd->ecclayout->oobavail; if (bbt[i] || bbt[i + 1]) continue; - addr = (i + 1) * mtd->erasesize - mtd->writesize; + addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; prandom_bytes_state(&rnd_state, writebuf, sz * cnt); for (pg = 0; pg < cnt; ++pg) { ops.mode = MTD_OPS_AUTO_OOB; @@ -598,7 +598,7 @@ static int __init mtd_oobtest_init(void) continue; prandom_bytes_state(&rnd_state, writebuf, mtd->ecclayout->oobavail * 2); - addr = (i + 1) * mtd->erasesize - mtd->writesize; + addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; diff --git a/drivers/mtd/tests/pagetest.c b/drivers/mtd/tests/pagetest.c index ed2d3f656fd2..88296e888e9d 100644 --- a/drivers/mtd/tests/pagetest.c +++ b/drivers/mtd/tests/pagetest.c @@ -52,7 +52,7 @@ static struct rnd_state rnd_state; static int write_eraseblock(int ebnum) { - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize); cond_resched(); @@ -64,7 +64,7 @@ static int verify_eraseblock(int ebnum) uint32_t j; int err = 0, i; loff_t addr0, addrn; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) diff --git a/drivers/mtd/tests/readtest.c b/drivers/mtd/tests/readtest.c index 626e66d0f7e7..a54cf1511114 100644 --- a/drivers/mtd/tests/readtest.c +++ b/drivers/mtd/tests/readtest.c @@ -47,7 +47,7 @@ static int pgcnt; static int read_eraseblock_by_page(int ebnum) { int i, ret, err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; void *buf = iobuf; void *oobbuf = iobuf1; diff --git a/drivers/mtd/tests/speedtest.c b/drivers/mtd/tests/speedtest.c index 87ff6a29f84e..5ee9f7021020 100644 --- a/drivers/mtd/tests/speedtest.c +++ b/drivers/mtd/tests/speedtest.c @@ -55,7 +55,7 @@ static int multiblock_erase(int ebnum, int blocks) { int err; struct erase_info ei; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; memset(&ei, 0, sizeof(struct erase_info)); ei.mtd = mtd; @@ -80,7 +80,7 @@ static int multiblock_erase(int ebnum, int blocks) static int write_eraseblock(int ebnum) { - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; return mtdtest_write(mtd, addr, mtd->erasesize, iobuf); } @@ -88,7 +88,7 @@ static int write_eraseblock(int ebnum) static int write_eraseblock_by_page(int ebnum) { int i, err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; void *buf = iobuf; for (i = 0; i < pgcnt; i++) { @@ -106,7 +106,7 @@ static int write_eraseblock_by_2pages(int ebnum) { size_t sz = pgsize * 2; int i, n = pgcnt / 2, err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; void *buf = iobuf; for (i = 0; i < n; i++) { @@ -124,7 +124,7 @@ static int write_eraseblock_by_2pages(int ebnum) static int read_eraseblock(int ebnum) { - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; return mtdtest_read(mtd, addr, mtd->erasesize, iobuf); } @@ -132,7 +132,7 @@ static int read_eraseblock(int ebnum) static int read_eraseblock_by_page(int ebnum) { int i, err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; void *buf = iobuf; for (i = 0; i < pgcnt; i++) { @@ -150,7 +150,7 @@ static int read_eraseblock_by_2pages(int ebnum) { size_t sz = pgsize * 2; int i, n = pgcnt / 2, err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; void *buf = iobuf; for (i = 0; i < n; i++) { diff --git a/drivers/mtd/tests/subpagetest.c b/drivers/mtd/tests/subpagetest.c index a876371ad410..7b59ef522d5e 100644 --- a/drivers/mtd/tests/subpagetest.c +++ b/drivers/mtd/tests/subpagetest.c @@ -57,7 +57,7 @@ static int write_eraseblock(int ebnum) { size_t written; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, subpgsize); err = mtd_write(mtd, addr, subpgsize, &written, writebuf); @@ -92,7 +92,7 @@ static int write_eraseblock2(int ebnum) { size_t written; int err = 0, k; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; for (k = 1; k < 33; ++k) { if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) @@ -131,7 +131,7 @@ static int verify_eraseblock(int ebnum) { size_t read; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, subpgsize); clear_data(readbuf, subpgsize); @@ -192,7 +192,7 @@ static int verify_eraseblock2(int ebnum) { size_t read; int err = 0, k; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; for (k = 1; k < 33; ++k) { if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) @@ -227,7 +227,7 @@ static int verify_eraseblock_ff(int ebnum) uint32_t j; size_t read; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; memset(writebuf, 0xff, subpgsize); for (j = 0; j < mtd->erasesize / subpgsize; ++j) { -- GitLab From 31f754628cbb12c983600f22d9f0fed50dfe2134 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:22 -0700 Subject: [PATCH 0430/5088] mtd: use __packed shorthand Signed-off-by: Brian Norris --- drivers/mtd/mtdswap.c | 2 +- drivers/mtd/nand/sm_common.h | 2 +- include/linux/mtd/cfi.h | 22 +++++++++++----------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 48cf6f98df44..fc8b3d16cce7 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -145,7 +145,7 @@ struct mtdswap_dev { struct mtdswap_oobdata { __le16 magic; __le32 count; -} __attribute__((packed)); +} __packed; #define MTDSWAP_MAGIC_CLEAN 0x2095 #define MTDSWAP_MAGIC_DIRTY (MTDSWAP_MAGIC_CLEAN + 1) diff --git a/drivers/mtd/nand/sm_common.h b/drivers/mtd/nand/sm_common.h index 00f4a83359b2..d3e028e58b0f 100644 --- a/drivers/mtd/nand/sm_common.h +++ b/drivers/mtd/nand/sm_common.h @@ -18,7 +18,7 @@ struct sm_oob { uint8_t ecc2[3]; uint8_t lba_copy2[2]; uint8_t ecc1[3]; -} __attribute__((packed)); +} __packed; /* one sector is always 512 bytes, but it can consist of two nand pages */ diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index 37ef6b194089..299d7d31fe53 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -153,7 +153,7 @@ struct cfi_ident { uint16_t MaxBufWriteSize; uint8_t NumEraseRegions; uint32_t EraseRegionInfo[0]; /* Not host ordered */ -} __attribute__((packed)); +} __packed; /* Extended Query Structure for both PRI and ALT */ @@ -161,7 +161,7 @@ struct cfi_extquery { uint8_t pri[3]; uint8_t MajorVersion; uint8_t MinorVersion; -} __attribute__((packed)); +} __packed; /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */ @@ -180,7 +180,7 @@ struct cfi_pri_intelext { uint8_t FactProtRegSize; uint8_t UserProtRegSize; uint8_t extra[0]; -} __attribute__((packed)); +} __packed; struct cfi_intelext_otpinfo { uint32_t ProtRegAddr; @@ -188,7 +188,7 @@ struct cfi_intelext_otpinfo { uint8_t FactProtRegSize; uint16_t UserGroups; uint8_t UserProtRegSize; -} __attribute__((packed)); +} __packed; struct cfi_intelext_blockinfo { uint16_t NumIdentBlocks; @@ -196,7 +196,7 @@ struct cfi_intelext_blockinfo { uint16_t MinBlockEraseCycles; uint8_t BitsPerCell; uint8_t BlockCap; -} __attribute__((packed)); +} __packed; struct cfi_intelext_regioninfo { uint16_t NumIdentPartitions; @@ -205,7 +205,7 @@ struct cfi_intelext_regioninfo { uint8_t NumOpAllowedSimEraMode; uint8_t NumBlockTypes; struct cfi_intelext_blockinfo BlockTypes[1]; -} __attribute__((packed)); +} __packed; struct cfi_intelext_programming_regioninfo { uint8_t ProgRegShift; @@ -214,7 +214,7 @@ struct cfi_intelext_programming_regioninfo { uint8_t Reserved2; uint8_t ControlInvalid; uint8_t Reserved3; -} __attribute__((packed)); +} __packed; /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ @@ -233,7 +233,7 @@ struct cfi_pri_amdstd { uint8_t VppMin; uint8_t VppMax; uint8_t TopBottom; -} __attribute__((packed)); +} __packed; /* Vendor-Specific PRI for Atmel chips (command set 0x0002) */ @@ -245,18 +245,18 @@ struct cfi_pri_atmel { uint8_t BottomBoot; uint8_t BurstMode; uint8_t PageMode; -} __attribute__((packed)); +} __packed; struct cfi_pri_query { uint8_t NumFields; uint32_t ProtField[1]; /* Not host ordered */ -} __attribute__((packed)); +} __packed; struct cfi_bri_query { uint8_t PageModeReadCap; uint8_t NumFields; uint32_t ConfField[1]; /* Not host ordered */ -} __attribute__((packed)); +} __packed; #define P_ID_NONE 0x0000 #define P_ID_INTEL_EXT 0x0001 -- GitLab From c115add9d073752d38f6517882dfeafe76fc4458 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:31 -0700 Subject: [PATCH 0431/5088] mtd: nand: denali: set proper error code on timeout The condition "if (irq_status == 0)" already ensures that one half of the ternary ?: is dead. I think this should probably actually be a FAIL, not a PASS. Caught by Coverity. Signed-off-by: Brian Norris Cc: Jamie Iles --- drivers/mtd/nand/denali.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index da0fcc224739..4885a0f573cd 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1062,9 +1062,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, dev_err(denali->dev, "timeout on write_page (type = %d)\n", raw_xfer); - denali->status = - (irq_status & INTR_STATUS__PROGRAM_FAIL) ? - NAND_STATUS_FAIL : PASS; + denali->status = NAND_STATUS_FAIL; } denali_enable_dma(denali, false); -- GitLab From b033e1aac9afd314add799b6cd2a5489f892757f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:44 -0700 Subject: [PATCH 0432/5088] mtd: nandsim: fix integer widening This multiplication should be done in 64-bit, not 32-bit. Caught by Coverity. Signed-off-by: Brian Norris --- drivers/mtd/nand/nandsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 4f0d83648e5a..7dc1dd28d896 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -827,7 +827,7 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd) NS_ERR("invalid badblocks.\n"); return -EINVAL; } - offset = erase_block_no * ns->geom.secsz; + offset = (loff_t)erase_block_no * ns->geom.secsz; if (mtd_block_markbad(mtd, offset)) { NS_ERR("invalid badblocks.\n"); return -EINVAL; -- GitLab From 7a6f43958a53020f85818ff5c895623e88781fd6 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:56 -0700 Subject: [PATCH 0433/5088] mtd: maps: solutionengine: drop excess dependency Already depends on SOLUTION_ENGINE, so we don't need the SUPERH dependency too. Signed-off-by: Brian Norris --- drivers/mtd/maps/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 21b2874a303b..ba801d2c6dcc 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -249,7 +249,7 @@ config MTD_CFI_FLAGADM config MTD_SOLUTIONENGINE tristate "CFI Flash device mapped on Hitachi SolutionEngine" - depends on SUPERH && SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS + depends on SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS help This enables access to the flash chips on the Hitachi SolutionEngine and similar boards. Say 'Y' if you are building a kernel for such a board. -- GitLab From 537ab1bd47d6518e8a40207a80dd0c2c4bc43aed Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:08:03 -0700 Subject: [PATCH 0434/5088] mtd: nand: fix integer widening problems chip->pagebuf is a 32-bit type (int), so the shift will only be applied as 32-bit. Fix this for 64-bit safety. Caught by Coverity. Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1a27c2da29ff..ae6e7c47f8e2 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2409,8 +2409,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; /* Invalidate the page cache, when we write to the cached page */ - if (to <= (chip->pagebuf << chip->page_shift) && - (chip->pagebuf << chip->page_shift) < (to + ops->len)) + if (to <= ((loff_t)chip->pagebuf << chip->page_shift) && + ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; /* Don't allow multipage oob writes with offset */ -- GitLab From 1cc8d8413327a684cd5e93cd52ececb0223bb40b Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:08:13 -0700 Subject: [PATCH 0435/5088] mtd: terminate user-provided string Noticed by Coverity as a potential security issue. Signed-off-by: Brian Norris --- drivers/mtd/mtdchar.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index a0f54e80670c..53563955931b 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -549,6 +549,9 @@ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd, if (mtd_is_partition(mtd)) return -EINVAL; + /* Sanitize user input */ + p.devname[BLKPG_DEVNAMELTH - 1] = '\0'; + return mtd_add_partition(mtd, p.devname, p.start, p.length); case BLKPG_DEL_PARTITION: -- GitLab From ff0a215438cf7be0a652cb3457f562539bd40b22 Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Tue, 5 Aug 2014 18:38:52 +0800 Subject: [PATCH 0436/5088] mtd: atmel_nand: NFC: fix mtd_nandbiterrs.ko test fail when using sram write When enable NFC sram write, it will failed the mtd_nandbiterrs.ko test. As in driver's nfc_sram_write_page(), if ops->mode equal to MTD_OSP_RAW, driver assumes the data buffer contains one page data and one oob data followed. And driver will write the page data and oob data to nand. But this is wrong implementation. Since the data buffer don't contains the oob data to write. We should write the chip->oob_poi to nand's oob. So this patch fix it by writing the oob data from chip->oob_poi. Signed-off-by: Josh Wu Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 0abc965caedf..9c5f717bda54 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1907,15 +1907,7 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (offset || (data_len < mtd->writesize)) return -EINVAL; - cfg = nfc_readl(host->nfc->hsmc_regs, CFG); len = mtd->writesize; - - if (unlikely(raw)) { - len += mtd->oobsize; - nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE); - } else - nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE); - /* Copy page data to sram that will write to nand via NFC */ if (use_dma) { if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0) @@ -1925,6 +1917,15 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip, memcpy32_toio(sram, buf, len); } + cfg = nfc_readl(host->nfc->hsmc_regs, CFG); + if (unlikely(raw) && oob_required) { + memcpy32_toio(sram + len, chip->oob_poi, mtd->oobsize); + len += mtd->oobsize; + nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE); + } else { + nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE); + } + if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) /* * When use NFC sram, need set up PMECC before send -- GitLab From bd8898db3e03147d9d7ddd48876fb3f3bcbab6c1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 9 Aug 2014 19:07:53 +0200 Subject: [PATCH 0437/5088] mtd: nand: Use ULL-suffix for big u64 constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/mtd/nand/nand_timings.c:45: warning: integer constant is too large for ‘long’ type [ Editorial note: This is a false warning. Looking at ISO draft N1124 (this is approximately C11, the first PDF I had lying around), section 6.4.4.1 (statement 5): "The type of an integer constant is the first of the corresponding list in which its value can be represented." So this should not be an overflow, and any toolchain that says so (e.g., GCC 4.4) is buggy. -Brian ] Signed-off-by: Geert Uytterhoeven Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_timings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c index 8b36253420fa..e81470a8ac67 100644 --- a/drivers/mtd/nand/nand_timings.c +++ b/drivers/mtd/nand/nand_timings.c @@ -42,7 +42,7 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = { .tRHZ_max = 200000, .tRLOH_min = 0, .tRP_min = 50000, - .tRST_max = 250000000000, + .tRST_max = 250000000000ULL, .tWB_max = 200000, .tRR_min = 40000, .tWC_min = 100000, -- GitLab From 02f8a24e7b1c253ee37edc684200c11300de23f9 Mon Sep 17 00:00:00 2001 From: Aaron Wu Date: Thu, 7 Aug 2014 11:43:49 +0800 Subject: [PATCH 0438/5088] mtd: gpio_flash: handle case where offset + len exceeds the window size Fix the bug in handling gpio flash read/write when offset + len from MTD exceeds the window size Signed-off-by: Aaron Wu [Brian: made some commentary edits. Also note that the BUG_ON() was provably false for all non-negative inputs (since x % y <= x), so we dropped it.] Signed-off-by: Brian Norris --- drivers/mtd/maps/gpio-addr-flash.c | 42 ++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index a4c477b9fdd6..2fb346091af2 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -99,22 +99,28 @@ static map_word gf_read(struct map_info *map, unsigned long ofs) * @from: flash offset to copy from * @len: how much to copy * - * We rely on the MTD layer to chunk up copies such that a single request here - * will not cross a window size. This allows us to only wiggle the GPIOs once - * before falling back to a normal memcpy. Reading the higher layer code shows - * that this is indeed the case, but add a BUG_ON() to future proof. + * The "from" region may straddle more than one window, so toggle the GPIOs for + * each window region before reading its data. */ static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { struct async_state *state = gf_map_info_to_state(map); - gf_set_gpios(state, from); + int this_len; - /* BUG if operation crosses the win_size */ - BUG_ON(!((from + len) % state->win_size <= (from + len))); + while (len) { + if ((from % state->win_size) + len > state->win_size) + this_len = state->win_size - (from % state->win_size); + else + this_len = len; - /* operation does not cross the win_size, so one shot it */ - memcpy_fromio(to, map->virt + (from % state->win_size), len); + gf_set_gpios(state, from); + memcpy_fromio(to, map->virt + (from % state->win_size), + this_len); + len -= this_len; + from += this_len; + to += this_len; + } } /** @@ -147,13 +153,21 @@ static void gf_copy_to(struct map_info *map, unsigned long to, { struct async_state *state = gf_map_info_to_state(map); - gf_set_gpios(state, to); + int this_len; + + while (len) { + if ((to % state->win_size) + len > state->win_size) + this_len = state->win_size - (to % state->win_size); + else + this_len = len; - /* BUG if operation crosses the win_size */ - BUG_ON(!((to + len) % state->win_size <= (to + len))); + gf_set_gpios(state, to); + memcpy_toio(map->virt + (to % state->win_size), from, len); - /* operation does not cross the win_size, so one shot it */ - memcpy_toio(map->virt + (to % state->win_size), from, len); + len -= this_len; + to += this_len; + from += this_len; + } } static const char * const part_probe_types[] = { -- GitLab From ab75e89c013d8fff8bd8a6e520d184c3da1a4583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 7 Aug 2014 09:47:01 +0200 Subject: [PATCH 0439/5088] mtd: spi-nor: remove duplicated w25q128 entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Acked-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 4dc0c8662265..2fea172dd530 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -624,7 +624,6 @@ const struct spi_device_id spi_nor_ids[] = { { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, -- GitLab From 54ea17a597b00e46b3720e75dd7595cd5dfa5670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 7 Aug 2014 09:47:02 +0200 Subject: [PATCH 0440/5088] mtd: spi-nor: drop jedec_probe /helper/ function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a one-liner doing no magic and its name may be confusing because it does not have to use JEDEC (e.g. when using alternative read_id). Signed-off-by: Rafał Miłecki Acked-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 2fea172dd530..03e0ab8b2086 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -671,11 +671,6 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) return ERR_PTR(-ENODEV); } -static const struct spi_device_id *jedec_probe(struct spi_nor *nor) -{ - return nor->read_id(nor); -} - static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -958,7 +953,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, if (info->jedec_id) { const struct spi_device_id *jid; - jid = jedec_probe(nor); + jid = nor->read_id(nor); if (IS_ERR(jid)) { return PTR_ERR(jid); } else if (jid != id) { -- GitLab From 5d07f4202c5d63b73ba1734ed38e08461a689313 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 13 Aug 2014 21:19:53 +0200 Subject: [PATCH 0441/5088] sched: s/do_each_thread/for_each_process_thread/ in core.c Change kernel/sched/core.c to use for_each_process_thread(). Signed-off-by: Oleg Nesterov Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Hidetoshi Seto Cc: Frank Mayhar Cc: Frederic Weisbecker Cc: Andrew Morton Cc: Sanjay Rao Cc: Larry Woodman Cc: Rik van Riel Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20140813191953.GA19315@redhat.com Signed-off-by: Ingo Molnar --- kernel/sched/core.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 7d1ec6e60535..4f2826f46e95 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4505,7 +4505,7 @@ void show_state_filter(unsigned long state_filter) " task PC stack pid father\n"); #endif rcu_read_lock(); - do_each_thread(g, p) { + for_each_process_thread(g, p) { /* * reset the NMI-timeout, listing all files on a slow * console might take a lot of time: @@ -4513,7 +4513,7 @@ void show_state_filter(unsigned long state_filter) touch_nmi_watchdog(); if (!state_filter || (p->state & state_filter)) sched_show_task(p); - } while_each_thread(g, p); + } touch_all_softlockup_watchdogs(); @@ -7137,7 +7137,7 @@ void normalize_rt_tasks(void) struct rq *rq; read_lock_irqsave(&tasklist_lock, flags); - do_each_thread(g, p) { + for_each_process_thread(g, p) { /* * Only normalize user tasks: */ @@ -7168,8 +7168,7 @@ void normalize_rt_tasks(void) __task_rq_unlock(rq); raw_spin_unlock(&p->pi_lock); - } while_each_thread(g, p); - + } read_unlock_irqrestore(&tasklist_lock, flags); } @@ -7357,10 +7356,10 @@ static inline int tg_has_rt_tasks(struct task_group *tg) { struct task_struct *g, *p; - do_each_thread(g, p) { + for_each_process_thread(g, p) { if (rt_task(p) && task_rq(p)->rt.tg == tg) return 1; - } while_each_thread(g, p); + } return 0; } -- GitLab From d38e83c715270cc2e137bbf6f25206c8c023896b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 13 Aug 2014 21:19:56 +0200 Subject: [PATCH 0442/5088] sched: s/do_each_thread/for_each_process_thread/ in debug.c Change kernel/sched/debug.c to use for_each_process_thread(). Signed-off-by: Oleg Nesterov Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Hidetoshi Seto Cc: Frank Mayhar Cc: Frederic Weisbecker Cc: Andrew Morton Cc: Sanjay Rao Cc: Larry Woodman Cc: Rik van Riel Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20140813191956.GA19324@redhat.com Signed-off-by: Ingo Molnar --- kernel/sched/debug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 627b3c34b821..c7fe1ea0e8ab 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -160,14 +160,12 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu) "----------------------------------------------------\n"); read_lock_irqsave(&tasklist_lock, flags); - - do_each_thread(g, p) { + for_each_process_thread(g, p) { if (task_cpu(p) != rq_cpu) continue; print_task(m, rq, p); - } while_each_thread(g, p); - + } read_unlock_irqrestore(&tasklist_lock, flags); } -- GitLab From 1e4dda08b4c39b3d8f4a3ee7269d49e0200c8af8 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 13 Aug 2014 21:20:00 +0200 Subject: [PATCH 0443/5088] sched: Change thread_group_cputime() to use for_each_thread() Change thread_group_cputime() to use for_each_thread() instead of buggy while_each_thread(). This also makes the pid_alive() check unnecessary. Signed-off-by: Oleg Nesterov Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Hidetoshi Seto Cc: Frank Mayhar Cc: Frederic Weisbecker Cc: Andrew Morton Cc: Sanjay Rao Cc: Larry Woodman Cc: Rik van Riel Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20140813192000.GA19327@redhat.com Signed-off-by: Ingo Molnar --- kernel/sched/cputime.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 72fdf06ef865..3e52836359ba 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -294,18 +294,12 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) times->sum_exec_runtime = sig->sum_sched_runtime; rcu_read_lock(); - /* make sure we can trust tsk->thread_group list */ - if (!likely(pid_alive(tsk))) - goto out; - - t = tsk; - do { + for_each_thread(tsk, t) { task_cputime(t, &utime, &stime); times->utime += utime; times->stime += stime; times->sum_exec_runtime += task_sched_runtime(t); - } while_each_thread(tsk, t); -out: + } rcu_read_unlock(); } -- GitLab From 5aface53d1a0ef7823215c4078fca8445995d006 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 13 Aug 2014 21:20:03 +0200 Subject: [PATCH 0444/5088] sched: Change autogroup_move_group() to use for_each_thread() Change autogroup_move_group() to use for_each_thread() instead of buggy while_each_thread(). Signed-off-by: Oleg Nesterov Signed-off-by: Peter Zijlstra Cc: Mike Galbraith Cc: Hidetoshi Seto Cc: Frank Mayhar Cc: Frederic Weisbecker Cc: Andrew Morton Cc: Sanjay Rao Cc: Larry Woodman Cc: Rik van Riel Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20140813192003.GA19334@redhat.com Signed-off-by: Ingo Molnar --- kernel/sched/auto_group.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kernel/sched/auto_group.c b/kernel/sched/auto_group.c index e73efba98301..8a2e230fb86a 100644 --- a/kernel/sched/auto_group.c +++ b/kernel/sched/auto_group.c @@ -148,11 +148,8 @@ autogroup_move_group(struct task_struct *p, struct autogroup *ag) if (!ACCESS_ONCE(sysctl_sched_autogroup_enabled)) goto out; - t = p; - do { + for_each_thread(p, t) sched_move_task(t); - } while_each_thread(p, t); - out: unlock_task_sighand(p, &flags); autogroup_kref_put(prev); -- GitLab From 8b06c55bdb8b402cb4814e83dc4b1cb245fcc9f5 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Wed, 13 Aug 2014 13:28:12 -0400 Subject: [PATCH 0445/5088] sched: Match declaration with definition Match the declaration of runqueues with the definition. Signed-off-by: Pranith Kumar Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1407950893-32731-1-git-send-email-bobby.prani@gmail.com Signed-off-by: Ingo Molnar --- kernel/sched/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 579712f4e9d5..4c2b87fd5f52 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -647,7 +647,7 @@ static inline int cpu_of(struct rq *rq) #endif } -DECLARE_PER_CPU(struct rq, runqueues); +DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); #define cpu_rq(cpu) (&per_cpu(runqueues, (cpu))) #define this_rq() (&__get_cpu_var(runqueues)) -- GitLab From f36c019c79edb3a89920afae1b2b45987af1a112 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 6 Aug 2014 12:06:01 +0400 Subject: [PATCH 0446/5088] sched/fair: Fix reschedule which is generated on throttled cfs_rq (sched_entity::on_rq == 1) does not guarantee the task is pickable; changes on throttled cfs_rq must not lead to reschedule. Check for task_struct::on_rq instead. Signed-off-by: Kirill Tkhai Signed-off-by: Peter Zijlstra Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1407312361.8424.35.camel@tkhai Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 1413c44ce8a1..bc37bb97159f 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7494,7 +7494,7 @@ static void task_fork_fair(struct task_struct *p) static void prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio) { - if (!p->se.on_rq) + if (!p->on_rq) return; /* @@ -7550,15 +7550,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p) */ static void switched_to_fair(struct rq *rq, struct task_struct *p) { - struct sched_entity *se = &p->se; #ifdef CONFIG_FAIR_GROUP_SCHED + struct sched_entity *se = &p->se; /* * Since the real-depth could have been changed (only FAIR * class maintain depth value), reset depth properly. */ se->depth = se->parent ? se->parent->depth + 1 : 0; #endif - if (!se->on_rq) + if (!p->on_rq) return; /* -- GitLab From 700be564308bcfc217bd3515d634b56f0c3c1bbb Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Tue, 19 Aug 2014 22:31:14 -0400 Subject: [PATCH 0447/5088] perf symbols: Don't try to find DSOs in SYSV maps We are seeing a lot of the following with regards to SYSV memory Failed to open /SYSV0000279c, continuing without symbols We don't believe this memory will have DSO info, so treat it like the heap and stack for now and skip it to prevent the warning. Signed-off-by: Don Zickus Signed-off-by: Joe Mario Cc: Jiri Olsa Cc: Joe Mario Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1408501874-244377-1-git-send-email-dzickus@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/map.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 31b8905dd863..b7090596ac50 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -31,6 +31,7 @@ static inline int is_anon_memory(const char *filename) static inline int is_no_dso_memory(const char *filename) { return !strncmp(filename, "[stack", 6) || + !strncmp(filename, "/SYSV",5) || !strcmp(filename, "[heap]"); } -- GitLab From ad7e767a726dd7dffad45d7fcbf371094e7f2288 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Thu, 7 Aug 2014 00:27:00 -0700 Subject: [PATCH 0448/5088] perf tools powerpc: Explicitly include util/debug.h Looks like util/debug.h was indirectly included before and is no longer included now. pr_debug is left undefined and the build of perf tool fails on Powerpc. Explicitly include util/debug.h. Signed-off-by: Sukadev Bhattiprolu Acked-by: Jiri Olsa Cc: Jiri Olsa Cc: Michael Ellerman Link: http://lkml.kernel.org/r/20140807072700.GA17623@us.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/powerpc/util/skip-callchain-idx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index a7c23a4b3778..d73ef8bb08c7 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c @@ -15,6 +15,7 @@ #include "util/thread.h" #include "util/callchain.h" +#include "util/debug.h" /* * When saving the callchain on Power, the kernel conservatively saves -- GitLab From 8e4bebe0952af357e099147023af756baa466ede Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Thu, 7 Aug 2014 18:51:34 +0800 Subject: [PATCH 0449/5088] irqchip: hip04: Enable Hisilicon HiP04 interrupt controller HiP04 GIC is the variate of ARM GICv2. ARM GICv2 supports 8 cores. HiP04 GIC extends to support 16 cores. It results that bit fields in GIC_DIST_TARGET & GIC_DIST_SOFTINT are different from ARM GICv2. And the maximium IRQ is downgrade from 1020 to 510. Since different register offset & bitfields definitation breaks compartible with ARM GICv2, create a new hip04 irq driver. And this driver is derived from irq-gic.c to support the Hisilicon HiP04 interrupt controller, which is similar to the GIC, but deviates at some points. Support for power management, non-banked registers, cascaded GICs (and multiple controllers in general) and bigLittle support has been removed from the GIC driver. Affinity related functions have been adjusted to match the Hisilicon hardware implementation. Signed-off-by: Haojian Zhuang Link: https://lkml.kernel.org/r/1407408695-19626-9-git-send-email-haojian.zhuang@linaro.org Signed-off-by: Jason Cooper --- drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-hip04.c | 424 ++++++++++++++++++++++++++++++++++++ 2 files changed, 425 insertions(+) create mode 100644 drivers/irqchip/irq-hip04.c diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 73052ba9ca62..1dca5bc2cc43 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o +obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o obj-$(CONFIG_ARCH_MMP) += irq-mmp.o obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o obj-$(CONFIG_ARCH_MXS) += irq-mxs.o diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c new file mode 100644 index 000000000000..9c8f833522e6 --- /dev/null +++ b/drivers/irqchip/irq-hip04.c @@ -0,0 +1,424 @@ +/* + * Hisilicon HiP04 INTC + * + * Copyright (C) 2002-2014 ARM Limited. + * Copyright (c) 2013-2014 Hisilicon Ltd. + * Copyright (c) 2013-2014 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. + * + * Interrupt architecture for the HIP04 INTC: + * + * o There is one Interrupt Distributor, which receives interrupts + * from system devices and sends them to the Interrupt Controllers. + * + * o There is one CPU Interface per CPU, which sends interrupts sent + * by the Distributor, and interrupts generated locally, to the + * associated CPU. The base address of the CPU interface is usually + * aliased so that the same address points to different chips depending + * on the CPU it is accessed from. + * + * Note that IRQs 0-31 are special - they are local to each CPU. + * As such, the enable set/clear, pending set/clear and active bit + * registers are banked per-cpu for these sources. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "irq-gic-common.h" +#include "irqchip.h" + +#define HIP04_MAX_IRQS 510 + +struct hip04_irq_data { + void __iomem *dist_base; + void __iomem *cpu_base; + struct irq_domain *domain; + unsigned int nr_irqs; +}; + +static DEFINE_RAW_SPINLOCK(irq_controller_lock); + +/* + * The GIC mapping of CPU interfaces does not necessarily match + * the logical CPU numbering. Let's use a mapping as returned + * by the GIC itself. + */ +#define NR_HIP04_CPU_IF 16 +static u16 hip04_cpu_map[NR_HIP04_CPU_IF] __read_mostly; + +static struct hip04_irq_data hip04_data __read_mostly; + +static inline void __iomem *hip04_dist_base(struct irq_data *d) +{ + struct hip04_irq_data *hip04_data = irq_data_get_irq_chip_data(d); + return hip04_data->dist_base; +} + +static inline void __iomem *hip04_cpu_base(struct irq_data *d) +{ + struct hip04_irq_data *hip04_data = irq_data_get_irq_chip_data(d); + return hip04_data->cpu_base; +} + +static inline unsigned int hip04_irq(struct irq_data *d) +{ + return d->hwirq; +} + +/* + * Routines to acknowledge, disable and enable interrupts + */ +static void hip04_mask_irq(struct irq_data *d) +{ + u32 mask = 1 << (hip04_irq(d) % 32); + + raw_spin_lock(&irq_controller_lock); + writel_relaxed(mask, hip04_dist_base(d) + GIC_DIST_ENABLE_CLEAR + + (hip04_irq(d) / 32) * 4); + raw_spin_unlock(&irq_controller_lock); +} + +static void hip04_unmask_irq(struct irq_data *d) +{ + u32 mask = 1 << (hip04_irq(d) % 32); + + raw_spin_lock(&irq_controller_lock); + writel_relaxed(mask, hip04_dist_base(d) + GIC_DIST_ENABLE_SET + + (hip04_irq(d) / 32) * 4); + raw_spin_unlock(&irq_controller_lock); +} + +static void hip04_eoi_irq(struct irq_data *d) +{ + writel_relaxed(hip04_irq(d), hip04_cpu_base(d) + GIC_CPU_EOI); +} + +static int hip04_irq_set_type(struct irq_data *d, unsigned int type) +{ + void __iomem *base = hip04_dist_base(d); + unsigned int irq = hip04_irq(d); + + /* Interrupt configuration for SGIs can't be changed */ + if (irq < 16) + return -EINVAL; + + if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING) + return -EINVAL; + + raw_spin_lock(&irq_controller_lock); + + gic_configure_irq(irq, type, base, NULL); + + raw_spin_unlock(&irq_controller_lock); + + return 0; +} + +#ifdef CONFIG_SMP +static int hip04_irq_set_affinity(struct irq_data *d, + const struct cpumask *mask_val, + bool force) +{ + void __iomem *reg; + unsigned int cpu, shift = (hip04_irq(d) % 2) * 16; + u32 val, mask, bit; + + if (!force) + cpu = cpumask_any_and(mask_val, cpu_online_mask); + else + cpu = cpumask_first(mask_val); + + if (cpu >= NR_HIP04_CPU_IF || cpu >= nr_cpu_ids) + return -EINVAL; + + raw_spin_lock(&irq_controller_lock); + reg = hip04_dist_base(d) + GIC_DIST_TARGET + ((hip04_irq(d) * 2) & ~3); + mask = 0xffff << shift; + bit = hip04_cpu_map[cpu] << shift; + val = readl_relaxed(reg) & ~mask; + writel_relaxed(val | bit, reg); + raw_spin_unlock(&irq_controller_lock); + + return IRQ_SET_MASK_OK; +} +#endif + +static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs) +{ + u32 irqstat, irqnr; + void __iomem *cpu_base = hip04_data.cpu_base; + + do { + irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); + irqnr = irqstat & GICC_IAR_INT_ID_MASK; + + if (likely(irqnr > 15 && irqnr <= HIP04_MAX_IRQS)) { + irqnr = irq_find_mapping(hip04_data.domain, irqnr); + handle_IRQ(irqnr, regs); + continue; + } + if (irqnr < 16) { + writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); +#ifdef CONFIG_SMP + handle_IPI(irqnr, regs); +#endif + continue; + } + break; + } while (1); +} + +static struct irq_chip hip04_irq_chip = { + .name = "HIP04 INTC", + .irq_mask = hip04_mask_irq, + .irq_unmask = hip04_unmask_irq, + .irq_eoi = hip04_eoi_irq, + .irq_set_type = hip04_irq_set_type, +#ifdef CONFIG_SMP + .irq_set_affinity = hip04_irq_set_affinity, +#endif +}; + +static u16 hip04_get_cpumask(struct hip04_irq_data *intc) +{ + void __iomem *base = intc->dist_base; + u32 mask, i; + + for (i = mask = 0; i < 32; i += 2) { + mask = readl_relaxed(base + GIC_DIST_TARGET + i * 2); + mask |= mask >> 16; + if (mask) + break; + } + + if (!mask) + pr_crit("GIC CPU mask not found - kernel will fail to boot.\n"); + + return mask; +} + +static void __init hip04_irq_dist_init(struct hip04_irq_data *intc) +{ + unsigned int i; + u32 cpumask; + unsigned int nr_irqs = intc->nr_irqs; + void __iomem *base = intc->dist_base; + + writel_relaxed(0, base + GIC_DIST_CTRL); + + /* + * Set all global interrupts to this CPU only. + */ + cpumask = hip04_get_cpumask(intc); + cpumask |= cpumask << 16; + for (i = 32; i < nr_irqs; i += 2) + writel_relaxed(cpumask, base + GIC_DIST_TARGET + ((i * 2) & ~3)); + + gic_dist_config(base, nr_irqs, NULL); + + writel_relaxed(1, base + GIC_DIST_CTRL); +} + +static void hip04_irq_cpu_init(struct hip04_irq_data *intc) +{ + void __iomem *dist_base = intc->dist_base; + void __iomem *base = intc->cpu_base; + unsigned int cpu_mask, cpu = smp_processor_id(); + int i; + + /* + * Get what the GIC says our CPU mask is. + */ + BUG_ON(cpu >= NR_HIP04_CPU_IF); + cpu_mask = hip04_get_cpumask(intc); + hip04_cpu_map[cpu] = cpu_mask; + + /* + * Clear our mask from the other map entries in case they're + * still undefined. + */ + for (i = 0; i < NR_HIP04_CPU_IF; i++) + if (i != cpu) + hip04_cpu_map[i] &= ~cpu_mask; + + gic_cpu_config(dist_base, NULL); + + writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); + writel_relaxed(1, base + GIC_CPU_CTRL); +} + +#ifdef CONFIG_SMP +static void hip04_raise_softirq(const struct cpumask *mask, unsigned int irq) +{ + int cpu; + unsigned long flags, map = 0; + + raw_spin_lock_irqsave(&irq_controller_lock, flags); + + /* Convert our logical CPU mask into a physical one. */ + for_each_cpu(cpu, mask) + map |= hip04_cpu_map[cpu]; + + /* + * Ensure that stores to Normal memory are visible to the + * other CPUs before they observe us issuing the IPI. + */ + dmb(ishst); + + /* this always happens on GIC0 */ + writel_relaxed(map << 8 | irq, hip04_data.dist_base + GIC_DIST_SOFTINT); + + raw_spin_unlock_irqrestore(&irq_controller_lock, flags); +} +#endif + +static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + if (hw < 32) { + irq_set_percpu_devid(irq); + irq_set_chip_and_handler(irq, &hip04_irq_chip, + handle_percpu_devid_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); + } else { + irq_set_chip_and_handler(irq, &hip04_irq_chip, + handle_fasteoi_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + irq_set_chip_data(irq, d->host_data); + return 0; +} + +static int hip04_irq_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + unsigned long ret = 0; + + if (d->of_node != controller) + return -EINVAL; + if (intsize < 3) + return -EINVAL; + + /* Get the interrupt number and add 16 to skip over SGIs */ + *out_hwirq = intspec[1] + 16; + + /* For SPIs, we need to add 16 more to get the irq ID number */ + if (!intspec[0]) + *out_hwirq += 16; + + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; + + return ret; +} + +#ifdef CONFIG_SMP +static int hip04_irq_secondary_init(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) + hip04_irq_cpu_init(&hip04_data); + return NOTIFY_OK; +} + +/* + * Notifier for enabling the INTC CPU interface. Set an arbitrarily high + * priority because the GIC needs to be up before the ARM generic timers. + */ +static struct notifier_block hip04_irq_cpu_notifier = { + .notifier_call = hip04_irq_secondary_init, + .priority = 100, +}; +#endif + +static const struct irq_domain_ops hip04_irq_domain_ops = { + .map = hip04_irq_domain_map, + .xlate = hip04_irq_domain_xlate, +}; + +static int __init +hip04_of_init(struct device_node *node, struct device_node *parent) +{ + irq_hw_number_t hwirq_base = 16; + int nr_irqs, irq_base, i; + + if (WARN_ON(!node)) + return -ENODEV; + + hip04_data.dist_base = of_iomap(node, 0); + WARN(!hip04_data.dist_base, "fail to map hip04 intc dist registers\n"); + + hip04_data.cpu_base = of_iomap(node, 1); + WARN(!hip04_data.cpu_base, "unable to map hip04 intc cpu registers\n"); + + /* + * Initialize the CPU interface map to all CPUs. + * It will be refined as each CPU probes its ID. + */ + for (i = 0; i < NR_HIP04_CPU_IF; i++) + hip04_cpu_map[i] = 0xff; + + /* + * Find out how many interrupts are supported. + * The HIP04 INTC only supports up to 510 interrupt sources. + */ + nr_irqs = readl_relaxed(hip04_data.dist_base + GIC_DIST_CTR) & 0x1f; + nr_irqs = (nr_irqs + 1) * 32; + if (nr_irqs > HIP04_MAX_IRQS) + nr_irqs = HIP04_MAX_IRQS; + hip04_data.nr_irqs = nr_irqs; + + nr_irqs -= hwirq_base; /* calculate # of irqs to allocate */ + + irq_base = irq_alloc_descs(-1, hwirq_base, nr_irqs, numa_node_id()); + if (IS_ERR_VALUE(irq_base)) { + pr_err("failed to allocate IRQ numbers\n"); + return -EINVAL; + } + + hip04_data.domain = irq_domain_add_legacy(node, nr_irqs, irq_base, + hwirq_base, + &hip04_irq_domain_ops, + &hip04_data); + + if (WARN_ON(!hip04_data.domain)) + return -EINVAL; + +#ifdef CONFIG_SMP + set_smp_cross_call(hip04_raise_softirq); + register_cpu_notifier(&hip04_irq_cpu_notifier); +#endif + set_handle_irq(hip04_handle_irq); + + hip04_irq_dist_init(&hip04_data); + hip04_irq_cpu_init(&hip04_data); + + return 0; +} +IRQCHIP_DECLARE(hip04_intc, "hisilicon,hip04-intc", hip04_of_init); -- GitLab From da0c1e65b51a289540159663aa4b90ba2366bc21 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 20 Aug 2014 13:47:32 +0400 Subject: [PATCH 0450/5088] sched: Add wrapper for checking task_struct::on_rq Implement task_on_rq_queued() and use it everywhere instead of on_rq check. No functional changes. The only exception is we do not use the wrapper in check_for_tasks(), because it requires to export task_on_rq_queued() in global header files. Next patch in series would return it back, so we do not twist it from here to there. Signed-off-by: Kirill Tkhai Cc: Peter Zijlstra Cc: Paul Turner Cc: Oleg Nesterov Cc: Steven Rostedt Cc: Mike Galbraith Cc: Kirill Tkhai Cc: Tim Chen Cc: Nicolas Pitre Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1408528052.23412.87.camel@tkhai Signed-off-by: Ingo Molnar --- kernel/sched/core.c | 82 ++++++++++++++++++++-------------------- kernel/sched/deadline.c | 15 ++++---- kernel/sched/fair.c | 22 +++++------ kernel/sched/rt.c | 16 ++++---- kernel/sched/sched.h | 7 ++++ kernel/sched/stop_task.c | 2 +- 6 files changed, 76 insertions(+), 68 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 4f2826f46e95..a02b624fee6c 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1043,7 +1043,7 @@ void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags) * A queue event has occurred, and we're going to schedule. In * this case, we can save a useless back to back clock update. */ - if (rq->curr->on_rq && test_tsk_need_resched(rq->curr)) + if (task_on_rq_queued(rq->curr) && test_tsk_need_resched(rq->curr)) rq->skip_clock_update = 1; } @@ -1088,7 +1088,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu) static void __migrate_swap_task(struct task_struct *p, int cpu) { - if (p->on_rq) { + if (task_on_rq_queued(p)) { struct rq *src_rq, *dst_rq; src_rq = task_rq(p); @@ -1214,7 +1214,7 @@ static int migration_cpu_stop(void *data); unsigned long wait_task_inactive(struct task_struct *p, long match_state) { unsigned long flags; - int running, on_rq; + int running, queued; unsigned long ncsw; struct rq *rq; @@ -1252,7 +1252,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state) rq = task_rq_lock(p, &flags); trace_sched_wait_task(p); running = task_running(rq, p); - on_rq = p->on_rq; + queued = task_on_rq_queued(p); ncsw = 0; if (!match_state || p->state == match_state) ncsw = p->nvcsw | LONG_MIN; /* sets MSB */ @@ -1284,7 +1284,7 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state) * running right now), it's preempted, and we should * yield - it could be a while. */ - if (unlikely(on_rq)) { + if (unlikely(queued)) { ktime_t to = ktime_set(0, NSEC_PER_SEC/HZ); set_current_state(TASK_UNINTERRUPTIBLE); @@ -1478,7 +1478,7 @@ ttwu_stat(struct task_struct *p, int cpu, int wake_flags) static void ttwu_activate(struct rq *rq, struct task_struct *p, int en_flags) { activate_task(rq, p, en_flags); - p->on_rq = 1; + p->on_rq = TASK_ON_RQ_QUEUED; /* if a worker is waking up, notify workqueue */ if (p->flags & PF_WQ_WORKER) @@ -1537,7 +1537,7 @@ static int ttwu_remote(struct task_struct *p, int wake_flags) int ret = 0; rq = __task_rq_lock(p); - if (p->on_rq) { + if (task_on_rq_queued(p)) { /* check_preempt_curr() may use rq clock */ update_rq_clock(rq); ttwu_do_wakeup(rq, p, wake_flags); @@ -1678,7 +1678,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) success = 1; /* we're going to change ->state */ cpu = task_cpu(p); - if (p->on_rq && ttwu_remote(p, wake_flags)) + if (task_on_rq_queued(p) && ttwu_remote(p, wake_flags)) goto stat; #ifdef CONFIG_SMP @@ -1742,7 +1742,7 @@ static void try_to_wake_up_local(struct task_struct *p) if (!(p->state & TASK_NORMAL)) goto out; - if (!p->on_rq) + if (!task_on_rq_queued(p)) ttwu_activate(rq, p, ENQUEUE_WAKEUP); ttwu_do_wakeup(rq, p, 0); @@ -2095,7 +2095,7 @@ void wake_up_new_task(struct task_struct *p) init_task_runnable_average(p); rq = __task_rq_lock(p); activate_task(rq, p, 0); - p->on_rq = 1; + p->on_rq = TASK_ON_RQ_QUEUED; trace_sched_wakeup_new(p, true); check_preempt_curr(rq, p, WF_FORK); #ifdef CONFIG_SMP @@ -2444,7 +2444,7 @@ static u64 do_task_delta_exec(struct task_struct *p, struct rq *rq) * project cycles that may never be accounted to this * thread, breaking clock_gettime(). */ - if (task_current(rq, p) && p->on_rq) { + if (task_current(rq, p) && task_on_rq_queued(p)) { update_rq_clock(rq); ns = rq_clock_task(rq) - p->se.exec_start; if ((s64)ns < 0) @@ -2490,7 +2490,7 @@ unsigned long long task_sched_runtime(struct task_struct *p) * If we see ->on_cpu without ->on_rq, the task is leaving, and has * been accounted, so we're correct here as well. */ - if (!p->on_cpu || !p->on_rq) + if (!p->on_cpu || !task_on_rq_queued(p)) return p->se.sum_exec_runtime; #endif @@ -2794,7 +2794,7 @@ static void __sched __schedule(void) switch_count = &prev->nvcsw; } - if (prev->on_rq || rq->skip_clock_update < 0) + if (task_on_rq_queued(prev) || rq->skip_clock_update < 0) update_rq_clock(rq); next = pick_next_task(rq, prev); @@ -2959,7 +2959,7 @@ EXPORT_SYMBOL(default_wake_function); */ void rt_mutex_setprio(struct task_struct *p, int prio) { - int oldprio, on_rq, running, enqueue_flag = 0; + int oldprio, queued, running, enqueue_flag = 0; struct rq *rq; const struct sched_class *prev_class; @@ -2988,9 +2988,9 @@ void rt_mutex_setprio(struct task_struct *p, int prio) trace_sched_pi_setprio(p, prio); oldprio = p->prio; prev_class = p->sched_class; - on_rq = p->on_rq; + queued = task_on_rq_queued(p); running = task_current(rq, p); - if (on_rq) + if (queued) dequeue_task(rq, p, 0); if (running) p->sched_class->put_prev_task(rq, p); @@ -3030,7 +3030,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio) if (running) p->sched_class->set_curr_task(rq); - if (on_rq) + if (queued) enqueue_task(rq, p, enqueue_flag); check_class_changed(rq, p, prev_class, oldprio); @@ -3041,7 +3041,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio) void set_user_nice(struct task_struct *p, long nice) { - int old_prio, delta, on_rq; + int old_prio, delta, queued; unsigned long flags; struct rq *rq; @@ -3062,8 +3062,8 @@ void set_user_nice(struct task_struct *p, long nice) p->static_prio = NICE_TO_PRIO(nice); goto out_unlock; } - on_rq = p->on_rq; - if (on_rq) + queued = task_on_rq_queued(p); + if (queued) dequeue_task(rq, p, 0); p->static_prio = NICE_TO_PRIO(nice); @@ -3072,7 +3072,7 @@ void set_user_nice(struct task_struct *p, long nice) p->prio = effective_prio(p); delta = p->prio - old_prio; - if (on_rq) { + if (queued) { enqueue_task(rq, p, 0); /* * If the task increased its priority or is running and @@ -3344,7 +3344,7 @@ static int __sched_setscheduler(struct task_struct *p, { int newprio = dl_policy(attr->sched_policy) ? MAX_DL_PRIO - 1 : MAX_RT_PRIO - 1 - attr->sched_priority; - int retval, oldprio, oldpolicy = -1, on_rq, running; + int retval, oldprio, oldpolicy = -1, queued, running; int policy = attr->sched_policy; unsigned long flags; const struct sched_class *prev_class; @@ -3541,9 +3541,9 @@ static int __sched_setscheduler(struct task_struct *p, return 0; } - on_rq = p->on_rq; + queued = task_on_rq_queued(p); running = task_current(rq, p); - if (on_rq) + if (queued) dequeue_task(rq, p, 0); if (running) p->sched_class->put_prev_task(rq, p); @@ -3553,7 +3553,7 @@ static int __sched_setscheduler(struct task_struct *p, if (running) p->sched_class->set_curr_task(rq); - if (on_rq) { + if (queued) { /* * We enqueue to tail when the priority of a task is * increased (user space view). @@ -4568,7 +4568,7 @@ void init_idle(struct task_struct *idle, int cpu) rcu_read_unlock(); rq->curr = rq->idle = idle; - idle->on_rq = 1; + idle->on_rq = TASK_ON_RQ_QUEUED; #if defined(CONFIG_SMP) idle->on_cpu = 1; #endif @@ -4645,7 +4645,7 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) goto out; dest_cpu = cpumask_any_and(cpu_active_mask, new_mask); - if (p->on_rq) { + if (task_on_rq_queued(p)) { struct migration_arg arg = { p, dest_cpu }; /* Need help from migration thread: drop lock and wait. */ task_rq_unlock(rq, p, &flags); @@ -4695,7 +4695,7 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) * If we're not on a rq, the next wake-up will ensure we're * placed properly. */ - if (p->on_rq) { + if (task_on_rq_queued(p)) { dequeue_task(rq_src, p, 0); set_task_cpu(p, dest_cpu); enqueue_task(rq_dest, p, 0); @@ -4736,13 +4736,13 @@ void sched_setnuma(struct task_struct *p, int nid) { struct rq *rq; unsigned long flags; - bool on_rq, running; + bool queued, running; rq = task_rq_lock(p, &flags); - on_rq = p->on_rq; + queued = task_on_rq_queued(p); running = task_current(rq, p); - if (on_rq) + if (queued) dequeue_task(rq, p, 0); if (running) p->sched_class->put_prev_task(rq, p); @@ -4751,7 +4751,7 @@ void sched_setnuma(struct task_struct *p, int nid) if (running) p->sched_class->set_curr_task(rq); - if (on_rq) + if (queued) enqueue_task(rq, p, 0); task_rq_unlock(rq, p, &flags); } @@ -7116,13 +7116,13 @@ static void normalize_task(struct rq *rq, struct task_struct *p) .sched_policy = SCHED_NORMAL, }; int old_prio = p->prio; - int on_rq; + int queued; - on_rq = p->on_rq; - if (on_rq) + queued = task_on_rq_queued(p); + if (queued) dequeue_task(rq, p, 0); __setscheduler(rq, p, &attr); - if (on_rq) { + if (queued) { enqueue_task(rq, p, 0); resched_curr(rq); } @@ -7309,16 +7309,16 @@ void sched_offline_group(struct task_group *tg) void sched_move_task(struct task_struct *tsk) { struct task_group *tg; - int on_rq, running; + int queued, running; unsigned long flags; struct rq *rq; rq = task_rq_lock(tsk, &flags); running = task_current(rq, tsk); - on_rq = tsk->on_rq; + queued = task_on_rq_queued(tsk); - if (on_rq) + if (queued) dequeue_task(rq, tsk, 0); if (unlikely(running)) tsk->sched_class->put_prev_task(rq, tsk); @@ -7331,14 +7331,14 @@ void sched_move_task(struct task_struct *tsk) #ifdef CONFIG_FAIR_GROUP_SCHED if (tsk->sched_class->task_move_group) - tsk->sched_class->task_move_group(tsk, on_rq); + tsk->sched_class->task_move_group(tsk, queued); else #endif set_task_rq(tsk, task_cpu(tsk)); if (unlikely(running)) tsk->sched_class->set_curr_task(rq); - if (on_rq) + if (queued) enqueue_task(rq, tsk, 0); task_rq_unlock(rq, tsk, &flags); diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 255ce138b652..d21a8e0259d2 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -530,7 +530,7 @@ static enum hrtimer_restart dl_task_timer(struct hrtimer *timer) update_rq_clock(rq); dl_se->dl_throttled = 0; dl_se->dl_yielded = 0; - if (p->on_rq) { + if (task_on_rq_queued(p)) { enqueue_task_dl(rq, p, ENQUEUE_REPLENISH); if (task_has_dl_policy(rq->curr)) check_preempt_curr_dl(rq, p, 0); @@ -1030,7 +1030,7 @@ struct task_struct *pick_next_task_dl(struct rq *rq, struct task_struct *prev) * means a stop task can slip in, in which case we need to * re-start task selection. */ - if (rq->stop && rq->stop->on_rq) + if (rq->stop && task_on_rq_queued(rq->stop)) return RETRY_TASK; } @@ -1257,7 +1257,8 @@ static struct rq *find_lock_later_rq(struct task_struct *task, struct rq *rq) if (unlikely(task_rq(task) != rq || !cpumask_test_cpu(later_rq->cpu, &task->cpus_allowed) || - task_running(rq, task) || !task->on_rq)) { + task_running(rq, task) || + !task_on_rq_queued(task))) { double_unlock_balance(rq, later_rq); later_rq = NULL; break; @@ -1296,7 +1297,7 @@ static struct task_struct *pick_next_pushable_dl_task(struct rq *rq) BUG_ON(task_current(rq, p)); BUG_ON(p->nr_cpus_allowed <= 1); - BUG_ON(!p->on_rq); + BUG_ON(!task_on_rq_queued(p)); BUG_ON(!dl_task(p)); return p; @@ -1443,7 +1444,7 @@ static int pull_dl_task(struct rq *this_rq) dl_time_before(p->dl.deadline, this_rq->dl.earliest_dl.curr))) { WARN_ON(p == src_rq->curr); - WARN_ON(!p->on_rq); + WARN_ON(!task_on_rq_queued(p)); /* * Then we pull iff p has actually an earlier @@ -1596,7 +1597,7 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p) if (unlikely(p->dl.dl_throttled)) return; - if (p->on_rq && rq->curr != p) { + if (task_on_rq_queued(p) && rq->curr != p) { #ifdef CONFIG_SMP if (rq->dl.overloaded && push_dl_task(rq) && rq != task_rq(p)) /* Only reschedule if pushing failed */ @@ -1614,7 +1615,7 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p) static void prio_changed_dl(struct rq *rq, struct task_struct *p, int oldprio) { - if (p->on_rq || rq->curr == p) { + if (task_on_rq_queued(p) || rq->curr == p) { #ifdef CONFIG_SMP /* * This might be too much, but unfortunately diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index bc37bb97159f..9e6ca0d88f51 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7494,7 +7494,7 @@ static void task_fork_fair(struct task_struct *p) static void prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio) { - if (!p->on_rq) + if (!task_on_rq_queued(p)) return; /* @@ -7519,11 +7519,11 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p) * switched back to the fair class the enqueue_entity(.flags=0) will * do the right thing. * - * If it's on_rq, then the dequeue_entity(.flags=0) will already - * have normalized the vruntime, if it's !on_rq, then only when + * If it's queued, then the dequeue_entity(.flags=0) will already + * have normalized the vruntime, if it's !queued, then only when * the task is sleeping will it still have non-normalized vruntime. */ - if (!p->on_rq && p->state != TASK_RUNNING) { + if (!task_on_rq_queued(p) && p->state != TASK_RUNNING) { /* * Fix up our vruntime so that the current sleep doesn't * cause 'unlimited' sleep bonus. @@ -7558,7 +7558,7 @@ static void switched_to_fair(struct rq *rq, struct task_struct *p) */ se->depth = se->parent ? se->parent->depth + 1 : 0; #endif - if (!p->on_rq) + if (!task_on_rq_queued(p)) return; /* @@ -7604,7 +7604,7 @@ void init_cfs_rq(struct cfs_rq *cfs_rq) } #ifdef CONFIG_FAIR_GROUP_SCHED -static void task_move_group_fair(struct task_struct *p, int on_rq) +static void task_move_group_fair(struct task_struct *p, int queued) { struct sched_entity *se = &p->se; struct cfs_rq *cfs_rq; @@ -7623,7 +7623,7 @@ static void task_move_group_fair(struct task_struct *p, int on_rq) * fair sleeper stuff for the first placement, but who cares. */ /* - * When !on_rq, vruntime of the task has usually NOT been normalized. + * When !queued, vruntime of the task has usually NOT been normalized. * But there are some cases where it has already been normalized: * * - Moving a forked child which is waiting for being woken up by @@ -7634,14 +7634,14 @@ static void task_move_group_fair(struct task_struct *p, int on_rq) * To prevent boost or penalty in the new cfs_rq caused by delta * min_vruntime between the two cfs_rqs, we skip vruntime adjustment. */ - if (!on_rq && (!se->sum_exec_runtime || p->state == TASK_WAKING)) - on_rq = 1; + if (!queued && (!se->sum_exec_runtime || p->state == TASK_WAKING)) + queued = 1; - if (!on_rq) + if (!queued) se->vruntime -= cfs_rq_of(se)->min_vruntime; set_task_rq(p, task_cpu(p)); se->depth = se->parent ? se->parent->depth + 1 : 0; - if (!on_rq) { + if (!queued) { cfs_rq = cfs_rq_of(se); se->vruntime += cfs_rq->min_vruntime; #ifdef CONFIG_SMP diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 5f6edca4fafd..4feac8fcb47f 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1448,7 +1448,7 @@ pick_next_task_rt(struct rq *rq, struct task_struct *prev) * means a dl or stop task can slip in, in which case we need * to re-start task selection. */ - if (unlikely((rq->stop && rq->stop->on_rq) || + if (unlikely((rq->stop && task_on_rq_queued(rq->stop)) || rq->dl.dl_nr_running)) return RETRY_TASK; } @@ -1624,7 +1624,7 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) !cpumask_test_cpu(lowest_rq->cpu, tsk_cpus_allowed(task)) || task_running(rq, task) || - !task->on_rq)) { + !task_on_rq_queued(task))) { double_unlock_balance(rq, lowest_rq); lowest_rq = NULL; @@ -1658,7 +1658,7 @@ static struct task_struct *pick_next_pushable_task(struct rq *rq) BUG_ON(task_current(rq, p)); BUG_ON(p->nr_cpus_allowed <= 1); - BUG_ON(!p->on_rq); + BUG_ON(!task_on_rq_queued(p)); BUG_ON(!rt_task(p)); return p; @@ -1809,7 +1809,7 @@ static int pull_rt_task(struct rq *this_rq) */ if (p && (p->prio < this_rq->rt.highest_prio.curr)) { WARN_ON(p == src_rq->curr); - WARN_ON(!p->on_rq); + WARN_ON(!task_on_rq_queued(p)); /* * There's a chance that p is higher in priority @@ -1870,7 +1870,7 @@ static void set_cpus_allowed_rt(struct task_struct *p, BUG_ON(!rt_task(p)); - if (!p->on_rq) + if (!task_on_rq_queued(p)) return; weight = cpumask_weight(new_mask); @@ -1936,7 +1936,7 @@ static void switched_from_rt(struct rq *rq, struct task_struct *p) * we may need to handle the pulling of RT tasks * now. */ - if (!p->on_rq || rq->rt.rt_nr_running) + if (!task_on_rq_queued(p) || rq->rt.rt_nr_running) return; if (pull_rt_task(rq)) @@ -1970,7 +1970,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p) * If that current running task is also an RT task * then see if we can move to another run queue. */ - if (p->on_rq && rq->curr != p) { + if (task_on_rq_queued(p) && rq->curr != p) { #ifdef CONFIG_SMP if (p->nr_cpus_allowed > 1 && rq->rt.overloaded && /* Don't resched if we changed runqueues */ @@ -1989,7 +1989,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p) static void prio_changed_rt(struct rq *rq, struct task_struct *p, int oldprio) { - if (!p->on_rq) + if (!task_on_rq_queued(p)) return; if (rq->curr == p) { diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 4c2b87fd5f52..26566d0c67ac 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -15,6 +15,9 @@ struct rq; +/* task_struct::on_rq states: */ +#define TASK_ON_RQ_QUEUED 1 + extern __read_mostly int scheduler_running; extern unsigned long calc_load_update; @@ -942,6 +945,10 @@ static inline int task_running(struct rq *rq, struct task_struct *p) #endif } +static inline int task_on_rq_queued(struct task_struct *p) +{ + return p->on_rq == TASK_ON_RQ_QUEUED; +} #ifndef prepare_arch_switch # define prepare_arch_switch(next) do { } while (0) diff --git a/kernel/sched/stop_task.c b/kernel/sched/stop_task.c index bfe0edadbfbb..67426e529f59 100644 --- a/kernel/sched/stop_task.c +++ b/kernel/sched/stop_task.c @@ -28,7 +28,7 @@ pick_next_task_stop(struct rq *rq, struct task_struct *prev) { struct task_struct *stop = rq->stop; - if (!stop || !stop->on_rq) + if (!stop || !task_on_rq_queued(stop)) return NULL; put_prev_task(rq, prev); -- GitLab From cca26e8009d1939a6a5bf0200d276fa26f03e536 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 20 Aug 2014 13:47:42 +0400 Subject: [PATCH 0451/5088] sched: Teach scheduler to understand TASK_ON_RQ_MIGRATING state This is a new p->on_rq state which will be used to indicate that a task is in a process of migrating between two RQs. It allows to get rid of double_rq_lock(), which we used to use to change a rq of a queued task before. Let's consider an example. To move a task between src_rq and dst_rq we will do the following: raw_spin_lock(&src_rq->lock); /* p is a task which is queued on src_rq */ p = ...; dequeue_task(src_rq, p, 0); p->on_rq = TASK_ON_RQ_MIGRATING; set_task_cpu(p, dst_cpu); raw_spin_unlock(&src_rq->lock); /* * Both RQs are unlocked here. * Task p is dequeued from src_rq * but its on_rq value is not zero. */ raw_spin_lock(&dst_rq->lock); p->on_rq = TASK_ON_RQ_QUEUED; enqueue_task(dst_rq, p, 0); raw_spin_unlock(&dst_rq->lock); While p->on_rq is TASK_ON_RQ_MIGRATING, task is considered as "migrating", and other parallel scheduler actions with it are not available to parallel callers. The parallel caller is spining till migration is completed. The unavailable actions are changing of cpu affinity, changing of priority etc, in other words all the functionality which used to require task_rq(p)->lock before (and related to the task). To implement TASK_ON_RQ_MIGRATING support we primarily are using the following fact. Most of scheduler users (from which we are protecting a migrating task) use task_rq_lock() and __task_rq_lock() to get the lock of task_rq(p). These primitives know that task's cpu may change, and they are spining while the lock of the right RQ is not held. We add one more condition into them, so they will be also spinning until the migration is finished. Signed-off-by: Kirill Tkhai Cc: Peter Zijlstra Cc: Paul Turner Cc: Oleg Nesterov Cc: Steven Rostedt Cc: Mike Galbraith Cc: Kirill Tkhai Cc: Tim Chen Cc: Nicolas Pitre Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1408528062.23412.88.camel@tkhai Signed-off-by: Ingo Molnar --- kernel/sched/core.c | 12 +++++++++--- kernel/sched/sched.h | 6 ++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index a02b624fee6c..71b836034912 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -333,9 +333,12 @@ static inline struct rq *__task_rq_lock(struct task_struct *p) for (;;) { rq = task_rq(p); raw_spin_lock(&rq->lock); - if (likely(rq == task_rq(p))) + if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) return rq; raw_spin_unlock(&rq->lock); + + while (unlikely(task_on_rq_migrating(p))) + cpu_relax(); } } @@ -352,10 +355,13 @@ static struct rq *task_rq_lock(struct task_struct *p, unsigned long *flags) raw_spin_lock_irqsave(&p->pi_lock, *flags); rq = task_rq(p); raw_spin_lock(&rq->lock); - if (likely(rq == task_rq(p))) + if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) return rq; raw_spin_unlock(&rq->lock); raw_spin_unlock_irqrestore(&p->pi_lock, *flags); + + while (unlikely(task_on_rq_migrating(p))) + cpu_relax(); } } @@ -1678,7 +1684,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) success = 1; /* we're going to change ->state */ cpu = task_cpu(p); - if (task_on_rq_queued(p) && ttwu_remote(p, wake_flags)) + if (p->on_rq && ttwu_remote(p, wake_flags)) goto stat; #ifdef CONFIG_SMP diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 26566d0c67ac..aa0f73ba3777 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -17,6 +17,7 @@ struct rq; /* task_struct::on_rq states: */ #define TASK_ON_RQ_QUEUED 1 +#define TASK_ON_RQ_MIGRATING 2 extern __read_mostly int scheduler_running; @@ -950,6 +951,11 @@ static inline int task_on_rq_queued(struct task_struct *p) return p->on_rq == TASK_ON_RQ_QUEUED; } +static inline int task_on_rq_migrating(struct task_struct *p) +{ + return p->on_rq == TASK_ON_RQ_MIGRATING; +} + #ifndef prepare_arch_switch # define prepare_arch_switch(next) do { } while (0) #endif -- GitLab From a1e01829796aa7a993e28ffd7fee5c8d525be175 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 20 Aug 2014 13:47:50 +0400 Subject: [PATCH 0452/5088] sched: Remove double_rq_lock() from __migrate_task() Avoid double_rq_lock() and use TASK_ON_RQ_MIGRATING for __migrate_task(). The advantage is (obviously) not holding two rq->lock's at the same time and thereby increasing parallelism. The important point to note is that because we acquire dst->lock immediately after releasing src->lock the potential wait time of task_rq_lock() callers on TASK_ON_RQ_MIGRATING is not longer than it would have been in the double rq lock scenario. Signed-off-by: Kirill Tkhai Cc: Peter Zijlstra Cc: Paul Turner Cc: Oleg Nesterov Cc: Steven Rostedt Cc: Mike Galbraith Cc: Kirill Tkhai Cc: Tim Chen Cc: Nicolas Pitre Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1408528070.23412.89.camel@tkhai Signed-off-by: Ingo Molnar --- kernel/sched/core.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 71b836034912..a773c919d88d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4679,20 +4679,20 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr); */ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) { - struct rq *rq_dest, *rq_src; + struct rq *rq; int ret = 0; if (unlikely(!cpu_active(dest_cpu))) return ret; - rq_src = cpu_rq(src_cpu); - rq_dest = cpu_rq(dest_cpu); + rq = cpu_rq(src_cpu); raw_spin_lock(&p->pi_lock); - double_rq_lock(rq_src, rq_dest); + raw_spin_lock(&rq->lock); /* Already moved. */ if (task_cpu(p) != src_cpu) goto done; + /* Affinity changed (again). */ if (!cpumask_test_cpu(dest_cpu, tsk_cpus_allowed(p))) goto fail; @@ -4702,15 +4702,22 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) * placed properly. */ if (task_on_rq_queued(p)) { - dequeue_task(rq_src, p, 0); + dequeue_task(rq, p, 0); + p->on_rq = TASK_ON_RQ_MIGRATING; set_task_cpu(p, dest_cpu); - enqueue_task(rq_dest, p, 0); - check_preempt_curr(rq_dest, p, 0); + raw_spin_unlock(&rq->lock); + + rq = cpu_rq(dest_cpu); + raw_spin_lock(&rq->lock); + BUG_ON(task_rq(p) != rq); + p->on_rq = TASK_ON_RQ_QUEUED; + enqueue_task(rq, p, 0); + check_preempt_curr(rq, p, 0); } done: ret = 1; fail: - double_rq_unlock(rq_src, rq_dest); + raw_spin_unlock(&rq->lock); raw_spin_unlock(&p->pi_lock); return ret; } -- GitLab From e5673f280501298dbb56efa46e333cf64ee5080a Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 20 Aug 2014 13:48:01 +0400 Subject: [PATCH 0453/5088] sched/fair: Remove double_lock_balance() from active_load_balance_cpu_stop() Avoid double_rq_lock() and use the TASK_ON_RQ_MIGRATING state for active_load_balance_cpu_stop(). The advantage is (obviously) not holding two 'rq->lock's at the same time and thereby increasing parallelism. Further note that if there was no task to migrate we will not have acquired the second rq->lock at all. The important point to note is that because we acquire dst->lock immediately after releasing src->lock the potential wait time of task_rq_lock() callers on TASK_ON_RQ_MIGRATING is not longer than it would have been in the double rq lock scenario. Signed-off-by: Kirill Tkhai Cc: Peter Zijlstra Cc: Paul Turner Cc: Oleg Nesterov Cc: Steven Rostedt Cc: Mike Galbraith Cc: Kirill Tkhai Cc: Tim Chen Cc: Nicolas Pitre Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1408528081.23412.92.camel@tkhai Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 60 +++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 9e6ca0d88f51..7e5cf051c144 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5138,6 +5138,8 @@ static int task_hot(struct task_struct *p, struct lb_env *env) { s64 delta; + lockdep_assert_held(&env->src_rq->lock); + if (p->sched_class != &fair_sched_class) return 0; @@ -5257,6 +5259,9 @@ static int can_migrate_task(struct task_struct *p, struct lb_env *env) { int tsk_cache_hot = 0; + + lockdep_assert_held(&env->src_rq->lock); + /* * We do not migrate tasks that are: * 1) throttled_lb_pair, or @@ -5341,30 +5346,49 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env) } /* - * move_one_task tries to move exactly one task from busiest to this_rq, as + * detach_one_task() -- tries to dequeue exactly one task from env->src_rq, as * part of active balancing operations within "domain". - * Returns 1 if successful and 0 otherwise. * - * Called with both runqueues locked. + * Returns a task if successful and NULL otherwise. */ -static int move_one_task(struct lb_env *env) +static struct task_struct *detach_one_task(struct lb_env *env) { struct task_struct *p, *n; + lockdep_assert_held(&env->src_rq->lock); + list_for_each_entry_safe(p, n, &env->src_rq->cfs_tasks, se.group_node) { if (!can_migrate_task(p, env)) continue; - move_task(p, env); + deactivate_task(env->src_rq, p, 0); + p->on_rq = TASK_ON_RQ_MIGRATING; + set_task_cpu(p, env->dst_cpu); + /* - * Right now, this is only the second place move_task() - * is called, so we can safely collect move_task() - * stats here rather than inside move_task(). + * Right now, this is only the second place where + * lb_gained[env->idle] is updated (other is move_tasks) + * so we can safely collect stats here rather than + * inside move_tasks(). */ schedstat_inc(env->sd, lb_gained[env->idle]); - return 1; + return p; } - return 0; + return NULL; +} + +/* + * attach_one_task() -- attaches the task returned from detach_one_task() to + * its new rq. + */ +static void attach_one_task(struct rq *rq, struct task_struct *p) +{ + raw_spin_lock(&rq->lock); + BUG_ON(task_rq(p) != rq); + p->on_rq = TASK_ON_RQ_QUEUED; + activate_task(rq, p, 0); + check_preempt_curr(rq, p, 0); + raw_spin_unlock(&rq->lock); } static const unsigned int sched_nr_migrate_break = 32; @@ -6943,6 +6967,7 @@ static int active_load_balance_cpu_stop(void *data) int target_cpu = busiest_rq->push_cpu; struct rq *target_rq = cpu_rq(target_cpu); struct sched_domain *sd; + struct task_struct *p = NULL; raw_spin_lock_irq(&busiest_rq->lock); @@ -6962,9 +6987,6 @@ static int active_load_balance_cpu_stop(void *data) */ BUG_ON(busiest_rq == target_rq); - /* move a task from busiest_rq to target_rq */ - double_lock_balance(busiest_rq, target_rq); - /* Search for an sd spanning us and the target CPU. */ rcu_read_lock(); for_each_domain(target_cpu, sd) { @@ -6985,16 +7007,22 @@ static int active_load_balance_cpu_stop(void *data) schedstat_inc(sd, alb_count); - if (move_one_task(&env)) + p = detach_one_task(&env); + if (p) schedstat_inc(sd, alb_pushed); else schedstat_inc(sd, alb_failed); } rcu_read_unlock(); - double_unlock_balance(busiest_rq, target_rq); out_unlock: busiest_rq->active_balance = 0; - raw_spin_unlock_irq(&busiest_rq->lock); + raw_spin_unlock(&busiest_rq->lock); + + if (p) + attach_one_task(target_rq, p); + + local_irq_enable(); + return 0; } -- GitLab From 163122b7fcfa28c0e4a838fcc8043c616746802e Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Wed, 20 Aug 2014 13:48:29 +0400 Subject: [PATCH 0454/5088] sched/fair: Remove double_lock_balance() from load_balance() Avoid double_rq_lock() and use TASK_ON_RQ_MIGRATING for load_balance(). The advantage is (obviously) not holding two rq->lock's at the same time and thereby increasing parallelism. Further note that if there was no task to migrate we will not have acquired the second rq->lock at all. The important point to note is that because we acquire dst->lock immediately after releasing src->lock the potential wait time of task_rq_lock() callers on TASK_ON_RQ_MIGRATING is not longer than it would have been in the double rq lock scenario. Signed-off-by: Kirill Tkhai Cc: Peter Zijlstra Cc: Paul Turner Cc: Oleg Nesterov Cc: Steven Rostedt Cc: Mike Galbraith Cc: Kirill Tkhai Cc: Tim Chen Cc: Nicolas Pitre Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1408528109.23412.94.camel@tkhai Signed-off-by: Ingo Molnar --- kernel/sched/fair.c | 151 +++++++++++++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 52 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 7e5cf051c144..d3427a8f254b 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4709,7 +4709,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ return; /* - * This is possible from callers such as move_task(), in which we + * This is possible from callers such as attach_tasks(), in which we * unconditionally check_prempt_curr() after an enqueue (which may have * lead to a throttle). This both saves work and prevents false * next-buddy nomination below. @@ -5117,20 +5117,9 @@ struct lb_env { unsigned int loop_max; enum fbq_type fbq_type; + struct list_head tasks; }; -/* - * move_task - move a task from one runqueue to another runqueue. - * Both runqueues must be locked. - */ -static void move_task(struct task_struct *p, struct lb_env *env) -{ - deactivate_task(env->src_rq, p, 0); - set_task_cpu(p, env->dst_cpu); - activate_task(env->dst_rq, p, 0); - check_preempt_curr(env->dst_rq, p, 0); -} - /* * Is this task likely cache-hot: */ @@ -5345,6 +5334,18 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env) return 0; } +/* + * detach_task() -- detach the task for the migration specified in env + */ +static void detach_task(struct task_struct *p, struct lb_env *env) +{ + lockdep_assert_held(&env->src_rq->lock); + + deactivate_task(env->src_rq, p, 0); + p->on_rq = TASK_ON_RQ_MIGRATING; + set_task_cpu(p, env->dst_cpu); +} + /* * detach_one_task() -- tries to dequeue exactly one task from env->src_rq, as * part of active balancing operations within "domain". @@ -5361,15 +5362,13 @@ static struct task_struct *detach_one_task(struct lb_env *env) if (!can_migrate_task(p, env)) continue; - deactivate_task(env->src_rq, p, 0); - p->on_rq = TASK_ON_RQ_MIGRATING; - set_task_cpu(p, env->dst_cpu); + detach_task(p, env); /* * Right now, this is only the second place where - * lb_gained[env->idle] is updated (other is move_tasks) + * lb_gained[env->idle] is updated (other is detach_tasks) * so we can safely collect stats here rather than - * inside move_tasks(). + * inside detach_tasks(). */ schedstat_inc(env->sd, lb_gained[env->idle]); return p; @@ -5377,35 +5376,22 @@ static struct task_struct *detach_one_task(struct lb_env *env) return NULL; } -/* - * attach_one_task() -- attaches the task returned from detach_one_task() to - * its new rq. - */ -static void attach_one_task(struct rq *rq, struct task_struct *p) -{ - raw_spin_lock(&rq->lock); - BUG_ON(task_rq(p) != rq); - p->on_rq = TASK_ON_RQ_QUEUED; - activate_task(rq, p, 0); - check_preempt_curr(rq, p, 0); - raw_spin_unlock(&rq->lock); -} - static const unsigned int sched_nr_migrate_break = 32; /* - * move_tasks tries to move up to imbalance weighted load from busiest to - * this_rq, as part of a balancing operation within domain "sd". - * Returns 1 if successful and 0 otherwise. + * detach_tasks() -- tries to detach up to imbalance weighted load from + * busiest_rq, as part of a balancing operation within domain "sd". * - * Called with both runqueues locked. + * Returns number of detached tasks if successful and 0 otherwise. */ -static int move_tasks(struct lb_env *env) +static int detach_tasks(struct lb_env *env) { struct list_head *tasks = &env->src_rq->cfs_tasks; struct task_struct *p; unsigned long load; - int pulled = 0; + int detached = 0; + + lockdep_assert_held(&env->src_rq->lock); if (env->imbalance <= 0) return 0; @@ -5436,14 +5422,16 @@ static int move_tasks(struct lb_env *env) if ((load / 2) > env->imbalance) goto next; - move_task(p, env); - pulled++; + detach_task(p, env); + list_add(&p->se.group_node, &env->tasks); + + detached++; env->imbalance -= load; #ifdef CONFIG_PREEMPT /* * NEWIDLE balancing is a source of latency, so preemptible - * kernels will stop after the first task is pulled to minimize + * kernels will stop after the first task is detached to minimize * the critical section. */ if (env->idle == CPU_NEWLY_IDLE) @@ -5463,13 +5451,58 @@ static int move_tasks(struct lb_env *env) } /* - * Right now, this is one of only two places move_task() is called, - * so we can safely collect move_task() stats here rather than - * inside move_task(). + * Right now, this is one of only two places we collect this stat + * so we can safely collect detach_one_task() stats here rather + * than inside detach_one_task(). */ - schedstat_add(env->sd, lb_gained[env->idle], pulled); + schedstat_add(env->sd, lb_gained[env->idle], detached); - return pulled; + return detached; +} + +/* + * attach_task() -- attach the task detached by detach_task() to its new rq. + */ +static void attach_task(struct rq *rq, struct task_struct *p) +{ + lockdep_assert_held(&rq->lock); + + BUG_ON(task_rq(p) != rq); + p->on_rq = TASK_ON_RQ_QUEUED; + activate_task(rq, p, 0); + check_preempt_curr(rq, p, 0); +} + +/* + * attach_one_task() -- attaches the task returned from detach_one_task() to + * its new rq. + */ +static void attach_one_task(struct rq *rq, struct task_struct *p) +{ + raw_spin_lock(&rq->lock); + attach_task(rq, p); + raw_spin_unlock(&rq->lock); +} + +/* + * attach_tasks() -- attaches all tasks detached by detach_tasks() to their + * new rq. + */ +static void attach_tasks(struct lb_env *env) +{ + struct list_head *tasks = &env->tasks; + struct task_struct *p; + + raw_spin_lock(&env->dst_rq->lock); + + while (!list_empty(tasks)) { + p = list_first_entry(tasks, struct task_struct, se.group_node); + list_del_init(&p->se.group_node); + + attach_task(env->dst_rq, p); + } + + raw_spin_unlock(&env->dst_rq->lock); } #ifdef CONFIG_FAIR_GROUP_SCHED @@ -6603,6 +6636,7 @@ static int load_balance(int this_cpu, struct rq *this_rq, .loop_break = sched_nr_migrate_break, .cpus = cpus, .fbq_type = all, + .tasks = LIST_HEAD_INIT(env.tasks), }; /* @@ -6652,16 +6686,29 @@ static int load_balance(int this_cpu, struct rq *this_rq, env.loop_max = min(sysctl_sched_nr_migrate, busiest->nr_running); more_balance: - local_irq_save(flags); - double_rq_lock(env.dst_rq, busiest); + raw_spin_lock_irqsave(&busiest->lock, flags); /* * cur_ld_moved - load moved in current iteration * ld_moved - cumulative load moved across iterations */ - cur_ld_moved = move_tasks(&env); - ld_moved += cur_ld_moved; - double_rq_unlock(env.dst_rq, busiest); + cur_ld_moved = detach_tasks(&env); + + /* + * We've detached some tasks from busiest_rq. Every + * task is masked "TASK_ON_RQ_MIGRATING", so we can safely + * unlock busiest->lock, and we are able to be sure + * that nobody can manipulate the tasks in parallel. + * See task_rq_lock() family for the details. + */ + + raw_spin_unlock(&busiest->lock); + + if (cur_ld_moved) { + attach_tasks(&env); + ld_moved += cur_ld_moved; + } + local_irq_restore(flags); /* @@ -6797,7 +6844,7 @@ static int load_balance(int this_cpu, struct rq *this_rq, * If we've begun active balancing, start to back off. This * case may not be covered by the all_pinned logic if there * is only 1 task on the busy runqueue (because we don't call - * move_tasks). + * detach_tasks). */ if (sd->balance_interval < sd->max_interval) sd->balance_interval *= 2; -- GitLab From 8091c1f8ea2374695c105591179b1269fb5f2fbb Mon Sep 17 00:00:00 2001 From: Andreas Ruprecht Date: Wed, 20 Aug 2014 10:16:01 +0200 Subject: [PATCH 0455/5088] x86/apic/uv: Remove unnecessary #ifdef In the file x2apic_uv_x.c, some code is compiled conditionally depending on CONFIG_SMP. However, the file is only built, if CONFIG_X86_UV is enabled. CONFIG_X86_UV depends on CONFIG_NUMA, which itself depends on CONFIG_SMP, so the #ifdef will always evaluate to true, if the file is compiled. Thus, it is unnecessary and can be removed. Signed-off-by: Andreas Ruprecht Cc: David Rientjes Cc: Dimitri Sivanich Cc: Hedi Berriche Cc: Linus Torvalds Cc: Mike Travis Cc: Russ Anderson Link: http://lkml.kernel.org/r/1408522561-23389-1-git-send-email-rupran@einserver.de Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic/x2apic_uv_x.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 293b41df54ef..2f1b5e0df660 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -204,7 +204,6 @@ EXPORT_SYMBOL(sn_rtc_cycles_per_second); static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip) { -#ifdef CONFIG_SMP unsigned long val; int pnode; @@ -223,7 +222,6 @@ static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip) uv_write_global_mmr64(pnode, UVH_IPI_INT, val); atomic_set(&init_deasserted, 1); -#endif return 0; } -- GitLab From 06ed5c2bfacaf67039e87a213fa5d1cdde34246a Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Wed, 20 Aug 2014 16:02:59 +0200 Subject: [PATCH 0456/5088] kbuild: Make scripts executable The Makefiles call the respective interpreter explicitly, but this makes it easier to use the scripts manually. Signed-off-by: Michal Marek --- scripts/bootgraph.pl | 0 scripts/export_report.pl | 0 scripts/gcc-goto.sh | 0 scripts/gcc-ld | 0 scripts/gcc-version.sh | 0 scripts/gcc-x86_32-has-stack-protector.sh | 0 scripts/gcc-x86_64-has-stack-protector.sh | 0 scripts/gen_initramfs_list.sh | 0 scripts/headers_check.pl | 0 scripts/headers_install.sh | 0 scripts/kconfig/lxdialog/check-lxdialog.sh | 0 scripts/kconfig/streamline_config.pl | 0 scripts/link-vmlinux.sh | 0 scripts/markup_oops.pl | 0 scripts/mkmakefile | 0 scripts/mksysmap | 0 scripts/package/builddeb | 0 scripts/package/buildtar | 0 scripts/profile2linkerlist.pl | 0 scripts/rt-tester/rt-tester.py | 0 scripts/selinux/install_policy.sh | 0 scripts/tracing/draw_functrace.py | 0 scripts/xz_wrap.sh | 0 23 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/bootgraph.pl mode change 100644 => 100755 scripts/export_report.pl mode change 100644 => 100755 scripts/gcc-goto.sh mode change 100644 => 100755 scripts/gcc-ld mode change 100644 => 100755 scripts/gcc-version.sh mode change 100644 => 100755 scripts/gcc-x86_32-has-stack-protector.sh mode change 100644 => 100755 scripts/gcc-x86_64-has-stack-protector.sh mode change 100644 => 100755 scripts/gen_initramfs_list.sh mode change 100644 => 100755 scripts/headers_check.pl mode change 100644 => 100755 scripts/headers_install.sh mode change 100644 => 100755 scripts/kconfig/lxdialog/check-lxdialog.sh mode change 100644 => 100755 scripts/kconfig/streamline_config.pl mode change 100644 => 100755 scripts/link-vmlinux.sh mode change 100644 => 100755 scripts/markup_oops.pl mode change 100644 => 100755 scripts/mkmakefile mode change 100644 => 100755 scripts/mksysmap mode change 100644 => 100755 scripts/package/builddeb mode change 100644 => 100755 scripts/package/buildtar mode change 100644 => 100755 scripts/profile2linkerlist.pl mode change 100644 => 100755 scripts/rt-tester/rt-tester.py mode change 100644 => 100755 scripts/selinux/install_policy.sh mode change 100644 => 100755 scripts/tracing/draw_functrace.py mode change 100644 => 100755 scripts/xz_wrap.sh diff --git a/scripts/bootgraph.pl b/scripts/bootgraph.pl old mode 100644 new mode 100755 diff --git a/scripts/export_report.pl b/scripts/export_report.pl old mode 100644 new mode 100755 diff --git a/scripts/gcc-goto.sh b/scripts/gcc-goto.sh old mode 100644 new mode 100755 diff --git a/scripts/gcc-ld b/scripts/gcc-ld old mode 100644 new mode 100755 diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh old mode 100644 new mode 100755 diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh old mode 100644 new mode 100755 diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh old mode 100644 new mode 100755 diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh old mode 100644 new mode 100755 diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl old mode 100644 new mode 100755 diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh old mode 100644 new mode 100755 diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh old mode 100644 new mode 100755 diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl old mode 100644 new mode 100755 diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh old mode 100644 new mode 100755 diff --git a/scripts/markup_oops.pl b/scripts/markup_oops.pl old mode 100644 new mode 100755 diff --git a/scripts/mkmakefile b/scripts/mkmakefile old mode 100644 new mode 100755 diff --git a/scripts/mksysmap b/scripts/mksysmap old mode 100644 new mode 100755 diff --git a/scripts/package/builddeb b/scripts/package/builddeb old mode 100644 new mode 100755 diff --git a/scripts/package/buildtar b/scripts/package/buildtar old mode 100644 new mode 100755 diff --git a/scripts/profile2linkerlist.pl b/scripts/profile2linkerlist.pl old mode 100644 new mode 100755 diff --git a/scripts/rt-tester/rt-tester.py b/scripts/rt-tester/rt-tester.py old mode 100644 new mode 100755 diff --git a/scripts/selinux/install_policy.sh b/scripts/selinux/install_policy.sh old mode 100644 new mode 100755 diff --git a/scripts/tracing/draw_functrace.py b/scripts/tracing/draw_functrace.py old mode 100644 new mode 100755 diff --git a/scripts/xz_wrap.sh b/scripts/xz_wrap.sh old mode 100644 new mode 100755 -- GitLab From 36e15dd4027a9b088264758fea292b6e876b5cdd Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 20 Aug 2014 17:07:58 +0900 Subject: [PATCH 0457/5088] perf hists browser: Get rid of unused 'remaining' variable It seems that the 'remaining' variable is not used by any real code. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1408522080-26556-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 4892480e8298..2f34c6b6d5dc 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -488,14 +488,13 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse { struct rb_node *node; int first_row = row, width, offset = level * LEVEL_OFFSET_STEP; - u64 new_total, remaining; + u64 new_total; if (callchain_param.mode == CHAIN_GRAPH_REL) new_total = chain_node->children_hit; else new_total = total; - remaining = new_total; node = rb_first(&chain_node->rb_root); while (node) { struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); @@ -506,8 +505,6 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse int first = true; int extra_offset = 0; - remaining -= cumul; - list_for_each_entry(chain, &child->val, list) { char bf[1024], *alloc_str; const char *str; @@ -1084,7 +1081,7 @@ static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *bro { struct rb_node *node; int offset = level * LEVEL_OFFSET_STEP; - u64 new_total, remaining; + u64 new_total; int printed = 0; if (callchain_param.mode == CHAIN_GRAPH_REL) @@ -1092,7 +1089,6 @@ static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *bro else new_total = total; - remaining = new_total; node = rb_first(&chain_node->rb_root); while (node) { struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); @@ -1103,8 +1099,6 @@ static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *bro int first = true; int extra_offset = 0; - remaining -= cumul; - list_for_each_entry(chain, &child->val, list) { char bf[1024], *alloc_str; const char *str; -- GitLab From 2bfa152839e5adea66aa6309c94bf3a50a5d5d47 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 20 Aug 2014 17:07:56 +0900 Subject: [PATCH 0458/5088] perf hists browser: Fix children overhead dump When perf report runs on TUI, 'P' key dumps current screen to a file but it incorrectly displayed children overhead (as same of self overhead). This was because it fetched the value from self stats. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1408522080-26556-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/hist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index b5fa7019d2e2..75eb6ac821f8 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -304,7 +304,7 @@ static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ struct perf_hpp *hpp, struct hist_entry *he) \ { \ - return hpp__fmt_acc(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ + return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ hpp_entry_scnprintf, true); \ } -- GitLab From f4536ddd20d93b70d432b7ca5db873525e23c2c4 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 20 Aug 2014 17:07:57 +0900 Subject: [PATCH 0459/5088] perf hists browser: Factor out hist_browser__show_callchain_entry() Factor out duplicate callchain printing code into the hist_browser__ show_callchain_entry(). Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1408522080-26556-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 64 ++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 2f34c6b6d5dc..d42d8a8f3810 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -477,6 +477,29 @@ static char *callchain_list__sym_name(struct callchain_list *cl, return bf; } +static void hist_browser__show_callchain_entry(struct hist_browser *browser, + struct callchain_list *chain, + unsigned short row, int offset, + char folded_sign, const char *str, + bool *is_current_entry) +{ + int color, width; + + color = HE_COLORSET_NORMAL; + width = browser->b.width - (offset + 2); + if (ui_browser__is_current_entry(&browser->b, row)) { + browser->selection = &chain->ms; + color = HE_COLORSET_SELECTED; + *is_current_entry = true; + } + + ui_browser__set_color(&browser->b, color); + hist_browser__gotorc(browser, row, 0); + slsmg_write_nstring(" ", offset); + slsmg_printf("%c ", folded_sign); + slsmg_write_nstring(str, width); +} + #define LEVEL_OFFSET_STEP 3 static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser, @@ -487,7 +510,7 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse bool *is_current_entry) { struct rb_node *node; - int first_row = row, width, offset = level * LEVEL_OFFSET_STEP; + int first_row = row, offset = level * LEVEL_OFFSET_STEP; u64 new_total; if (callchain_param.mode == CHAIN_GRAPH_REL) @@ -508,7 +531,6 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse list_for_each_entry(chain, &child->val, list) { char bf[1024], *alloc_str; const char *str; - int color; bool was_first = first; if (first) @@ -534,19 +556,10 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse str = alloc_str; } - color = HE_COLORSET_NORMAL; - width = browser->b.width - (offset + extra_offset + 2); - if (ui_browser__is_current_entry(&browser->b, row)) { - browser->selection = &chain->ms; - color = HE_COLORSET_SELECTED; - *is_current_entry = true; - } - - ui_browser__set_color(&browser->b, color); - hist_browser__gotorc(browser, row, 0); - slsmg_write_nstring(" ", offset + extra_offset); - slsmg_printf("%c ", folded_sign); - slsmg_write_nstring(str, width); + hist_browser__show_callchain_entry(browser, chain, row, + offset + extra_offset, + folded_sign, str, + is_current_entry); free(alloc_str); if (++row == browser->b.rows) @@ -577,14 +590,12 @@ static int hist_browser__show_callchain_node(struct hist_browser *browser, bool *is_current_entry) { struct callchain_list *chain; - int first_row = row, - offset = level * LEVEL_OFFSET_STEP, - width = browser->b.width - offset; + int first_row = row; + int offset = level * LEVEL_OFFSET_STEP; char folded_sign = ' '; list_for_each_entry(chain, &node->val, list) { char bf[1024], *s; - int color; folded_sign = callchain_list__folded(chain); @@ -593,20 +604,11 @@ static int hist_browser__show_callchain_node(struct hist_browser *browser, continue; } - color = HE_COLORSET_NORMAL; - if (ui_browser__is_current_entry(&browser->b, row)) { - browser->selection = &chain->ms; - color = HE_COLORSET_SELECTED; - *is_current_entry = true; - } - s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso); - hist_browser__gotorc(browser, row, 0); - ui_browser__set_color(&browser->b, color); - slsmg_write_nstring(" ", offset); - slsmg_printf("%c ", folded_sign); - slsmg_write_nstring(s, width - 2); + hist_browser__show_callchain_entry(browser, chain, row, + offset, folded_sign, s, + is_current_entry); if (++row == browser->b.rows) goto out; -- GitLab From b7c71823f11158340b9d61325d3c44124650dc4e Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Fri, 15 Aug 2014 12:01:31 +0100 Subject: [PATCH 0460/5088] drm/i915/bdw: Don't write PDP in the legacy way when using LRCs This is mostly for correctness so that we know we are running the LR context correctly (this is, the PDPs are contained inside the context object). v2: Move the check to inside the enable PPGTT function. The switch happens in two places: the legacy context switch (that we won't hit when Execlists are enabled) and the PPGTT enable, which unfortunately we need. This would look much nicer if the ppgtt->enable was part of the ring init, where it logically belongs. v3: Move the check to the start of the enable PPGTT function. None of the legacy PPGTT enabling is required when using LRCs as the PPGTT is enabled in the context descriptor and the PDPs are written in the LRC. v4: Clarify comment based on review feedback. Signed-off-by: Oscar Mateo Signed-off-by: Thomas Daniel Reviewed-by: Damien Lespiau [danvet: Resolve conflicts with ppgtt_enable rework.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index d97b280861ee..4db237065610 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -826,6 +826,12 @@ static void gen8_ppgtt_enable(struct drm_device *dev) struct intel_engine_cs *ring; int j; + /* 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. */ + if (i915.enable_execlists) + return; + for_each_ring(ring, dev_priv, j) { I915_WRITE(RING_MODE_GEN7(ring), _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); -- GitLab From cc9130be805d955f0e06642e57741dd9df1fbc86 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:42 +0100 Subject: [PATCH 0461/5088] drm/i915/bdw: Make sure gpu reset still works with Execlists If we reset a ring after a hang, we have to make sure that we clear out all queued Execlists requests. v2: The ring is, at this point, already being correctly re-programmed for Execlists, and the hangcheck counters cleared. v3: Daniel suggests to drop the "if (execlists)" because the Execlists queue should be empty in legacy mode (which is true, if we do the INIT_LIST_HEAD). v4: Do the pending intel_runtime_pm_put Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 12 ++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 1 + 2 files changed, 13 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 32fa1e9eb844..aa4103bdd352 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2551,6 +2551,18 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, i915_gem_free_request(request); } + while (!list_empty(&ring->execlist_queue)) { + struct intel_ctx_submit_request *submit_req; + + submit_req = list_first_entry(&ring->execlist_queue, + struct intel_ctx_submit_request, + execlist_link); + list_del(&submit_req->execlist_link); + intel_runtime_pm_put(dev_priv); + i915_gem_context_unreference(submit_req->ctx); + kfree(submit_req); + } + /* These may not have been flush before the reset, do so now */ kfree(ring->preallocated_lazy_request); ring->preallocated_lazy_request = NULL; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 13543f8528c2..4fb1ec95ec08 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1612,6 +1612,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, ring->dev = dev; INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); + INIT_LIST_HEAD(&ring->execlist_queue); ringbuf->size = 32 * PAGE_SIZE; ringbuf->ring = ring; memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno)); -- GitLab From 71386ef9008817feebd863e46d8711ebe9e7cbbb Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:44 +0100 Subject: [PATCH 0462/5088] drm/i915/bdw: Disable semaphores for Execlists Up until recently, semaphores weren't enabled in BDW so we didn't care about them. But then Rodrigo came and enabled them: commit 521e62e49a42661a4ee0102644517dbe2f100a23 Author: Rodrigo Vivi drm/i915: Enable semaphores on BDW So now we have to explicitly disable them for Execlists until both features play nicely. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 2f112853c36f..117f5c16df74 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -481,6 +481,10 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) if (i915.semaphores >= 0) return i915.semaphores; + /* TODO: make semaphores and Execlists play nicely together */ + if (i915.enable_execlists) + return false; + /* Until we get further testing... */ if (IS_GEN8(dev)) return false; -- GitLab From 4ba70e448be91f52032595678c306e4aee2fae5c Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 7 Aug 2014 13:23:20 +0100 Subject: [PATCH 0463/5088] drm/i915/bdw: Display execlists info in debugfs v2: Warn and return if LRCs are not enabled. v3: Grab the Execlists spinlock (noticed by Daniel Vetter). Signed-off-by: Oscar Mateo v4: Lock the struct mutex for atomic state capture Signed-off-by: Thomas Daniel Reviewed-by: Damien Lespiau [danvet: Checkpatch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 81 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_lrc.c | 6 --- drivers/gpu/drm/i915/intel_lrc.h | 7 +++ 3 files changed, 88 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d42db6bc34e0..68335813ef4c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1721,6 +1721,86 @@ static int i915_context_status(struct seq_file *m, void *unused) return 0; } +static int i915_execlists(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *ring; + u32 status_pointer; + u8 read_pointer; + u8 write_pointer; + u32 status; + u32 ctx_id; + struct list_head *cursor; + int ring_id, i; + int ret; + + if (!i915.enable_execlists) { + seq_puts(m, "Logical Ring Contexts are disabled\n"); + return 0; + } + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + for_each_ring(ring, dev_priv, ring_id) { + struct intel_ctx_submit_request *head_req = NULL; + int count = 0; + unsigned long flags; + + seq_printf(m, "%s\n", ring->name); + + status = I915_READ(RING_EXECLIST_STATUS(ring)); + ctx_id = I915_READ(RING_EXECLIST_STATUS(ring) + 4); + seq_printf(m, "\tExeclist status: 0x%08X, context: %u\n", + status, ctx_id); + + status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring)); + seq_printf(m, "\tStatus pointer: 0x%08X\n", status_pointer); + + read_pointer = ring->next_context_status_buffer; + write_pointer = status_pointer & 0x07; + if (read_pointer > write_pointer) + write_pointer += 6; + seq_printf(m, "\tRead pointer: 0x%08X, write pointer 0x%08X\n", + read_pointer, write_pointer); + + for (i = 0; i < 6; i++) { + status = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + 8*i); + ctx_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + 8*i + 4); + + seq_printf(m, "\tStatus buffer %d: 0x%08X, context: %u\n", + i, status, ctx_id); + } + + spin_lock_irqsave(&ring->execlist_lock, flags); + list_for_each(cursor, &ring->execlist_queue) + count++; + head_req = list_first_entry_or_null(&ring->execlist_queue, + struct intel_ctx_submit_request, execlist_link); + spin_unlock_irqrestore(&ring->execlist_lock, flags); + + seq_printf(m, "\t%d requests in queue\n", count); + if (head_req) { + struct drm_i915_gem_object *ctx_obj; + + ctx_obj = head_req->ctx->engine[ring_id].state; + seq_printf(m, "\tHead request id: %u\n", + intel_execlists_ctx_id(ctx_obj)); + seq_printf(m, "\tHead request tail: %u\n", + head_req->tail); + } + + seq_putc(m, '\n'); + } + + mutex_unlock(&dev->struct_mutex); + + return 0; +} + static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data) { struct drm_info_node *node = m->private; @@ -3974,6 +4054,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_opregion", i915_opregion, 0}, {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, {"i915_context_status", i915_context_status, 0}, + {"i915_execlists", i915_execlists, 0}, {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0}, {"i915_swizzle_info", i915_swizzle_info, 0}, {"i915_ppgtt_info", i915_ppgtt_info, 0}, diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 6f6c5a931faf..cc923a96fa4c 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -46,12 +46,6 @@ #define GEN8_LR_CONTEXT_ALIGN 4096 -#define RING_ELSP(ring) ((ring)->mmio_base+0x230) -#define RING_EXECLIST_STATUS(ring) ((ring)->mmio_base+0x234) -#define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244) -#define RING_CONTEXT_STATUS_BUF(ring) ((ring)->mmio_base+0x370) -#define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0) - #define RING_EXECLIST_QFULL (1 << 0x2) #define RING_EXECLIST1_VALID (1 << 0x3) #define RING_EXECLIST0_VALID (1 << 0x4) diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 331c6c2ba376..117d1a4eb3b9 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -24,6 +24,13 @@ #ifndef _INTEL_LRC_H_ #define _INTEL_LRC_H_ +/* Execlists regs */ +#define RING_ELSP(ring) ((ring)->mmio_base+0x230) +#define RING_EXECLIST_STATUS(ring) ((ring)->mmio_base+0x234) +#define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244) +#define RING_CONTEXT_STATUS_BUF(ring) ((ring)->mmio_base+0x370) +#define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0) + /* Logical Rings */ void intel_logical_ring_stop(struct intel_engine_cs *ring); void intel_logical_ring_cleanup(struct intel_engine_cs *ring); -- GitLab From c9fe99bd4c4f8730207fed5e863d8f25224fd20b Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:46 +0100 Subject: [PATCH 0464/5088] drm/i915/bdw: Display context backing obj & ringbuffer info in debugfs Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau [danvet: Checkpatch.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 37 +++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 68335813ef4c..4f279cfe67b8 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1677,6 +1677,14 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) return 0; } +static void describe_ctx_ringbuf(struct seq_file *m, + struct intel_ringbuffer *ringbuf) +{ + seq_printf(m, " (ringbuffer, space: %d, head: %u, tail: %u, last head: %d)", + ringbuf->space, ringbuf->head, ringbuf->tail, + ringbuf->last_retired_head); +} + static int i915_context_status(struct seq_file *m, void *unused) { struct drm_info_node *node = m->private; @@ -1703,16 +1711,37 @@ static int i915_context_status(struct seq_file *m, void *unused) } list_for_each_entry(ctx, &dev_priv->context_list, link) { - if (ctx->legacy_hw_ctx.rcs_state == NULL) + if (!i915.enable_execlists && + ctx->legacy_hw_ctx.rcs_state == NULL) continue; seq_puts(m, "HW context "); describe_ctx(m, ctx); - for_each_ring(ring, dev_priv, i) + for_each_ring(ring, dev_priv, i) { if (ring->default_context == ctx) - seq_printf(m, "(default context %s) ", ring->name); + seq_printf(m, "(default context %s) ", + ring->name); + } + + if (i915.enable_execlists) { + seq_putc(m, '\n'); + for_each_ring(ring, dev_priv, i) { + struct drm_i915_gem_object *ctx_obj = + ctx->engine[i].state; + struct intel_ringbuffer *ringbuf = + ctx->engine[i].ringbuf; + + seq_printf(m, "%s: ", ring->name); + if (ctx_obj) + describe_obj(m, ctx_obj); + if (ringbuf) + describe_ctx_ringbuf(m, ringbuf); + seq_putc(m, '\n'); + } + } else { + describe_obj(m, ctx->legacy_hw_ctx.rcs_state); + } - describe_obj(m, ctx->legacy_hw_ctx.rcs_state); seq_putc(m, '\n'); } -- GitLab From c0ab1ae9028f14bcb7bfb655bd2120c60681c479 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 7 Aug 2014 13:24:26 +0100 Subject: [PATCH 0465/5088] drm/i915/bdw: Print context state in debugfs This has turned out to be really handy in debug so far. Update: Since writing this patch, I've gotten similar code upstream for error state. I've used it quite a bit in debugfs however, and I'd like to keep it here at least until preemption is working. Signed-off-by: Ben Widawsky This patch was accidentally dropped in the first Execlists version, and it has been very useful indeed. Put it back again, but as a standalone debugfs file. Signed-off-by: Oscar Mateo v2: Take the device struct_mutex rather than mode_config mutex for atomic state capture. Signed-off-by: Thomas Daniel Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4f279cfe67b8..6c82bdaa0822 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1750,6 +1750,57 @@ static int i915_context_status(struct seq_file *m, void *unused) return 0; } +static int i915_dump_lrc(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *ring; + struct intel_context *ctx; + int ret, i; + + if (!i915.enable_execlists) { + seq_printf(m, "Logical Ring Contexts are disabled\n"); + return 0; + } + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + list_for_each_entry(ctx, &dev_priv->context_list, link) { + for_each_ring(ring, dev_priv, i) { + struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state; + + if (ring->default_context == ctx) + continue; + + if (ctx_obj) { + struct page *page = i915_gem_object_get_page(ctx_obj, 1); + uint32_t *reg_state = kmap_atomic(page); + int j; + + seq_printf(m, "CONTEXT: %s %u\n", ring->name, + intel_execlists_ctx_id(ctx_obj)); + + for (j = 0; j < 0x600 / sizeof(u32) / 4; j += 4) { + seq_printf(m, "\t[0x%08lx] 0x%08x 0x%08x 0x%08x 0x%08x\n", + i915_gem_obj_ggtt_offset(ctx_obj) + 4096 + (j * 4), + reg_state[j], reg_state[j + 1], + reg_state[j + 2], reg_state[j + 3]); + } + kunmap_atomic(reg_state); + + seq_putc(m, '\n'); + } + } + } + + mutex_unlock(&dev->struct_mutex); + + return 0; +} + static int i915_execlists(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *)m->private; @@ -4083,6 +4134,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_opregion", i915_opregion, 0}, {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, {"i915_context_status", i915_context_status, 0}, + {"i915_dump_lrc", i915_dump_lrc, 0}, {"i915_execlists", i915_execlists, 0}, {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0}, {"i915_swizzle_info", i915_swizzle_info, 0}, -- GitLab From 73e4d07f8ae9cff8c869d73df4e299a3a6f5ad98 Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:48 +0100 Subject: [PATCH 0466/5088] drm/i915/bdw: Document Logical Rings, LR contexts and Execlists Add theory of operation notes to intel_lrc.c and comments to externally visible functions. v2: Add notes on logical ring context creation. v3: Use kerneldoc. v4: Integrate it in the DocBook template. Signed-off-by: Thomas Daniel (v1) Signed-off-by: Oscar Mateo (v2, v3) Reviewed-by: Damien Lespiau [danvet: Drop hunk about render ring init function since that's not yet merged.] Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 5 + drivers/gpu/drm/i915/intel_lrc.c | 203 ++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_lrc.h | 30 +++++ 3 files changed, 237 insertions(+), 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 972759489376..689e3e38b9c3 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -3919,6 +3919,11 @@ int num_ioctls; !Pdrivers/gpu/drm/i915/i915_cmd_parser.c batch buffer command parser !Idrivers/gpu/drm/i915/i915_cmd_parser.c + + Logical Rings, Logical Ring Contexts and Execlists +!Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists +!Idrivers/gpu/drm/i915/intel_lrc.c + diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index cc923a96fa4c..c096b9b7f22a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -28,13 +28,108 @@ * */ -/* +/** + * DOC: Logical Rings, Logical Ring Contexts and Execlists + * + * Motivation: * GEN8 brings an expansion of the HW contexts: "Logical Ring Contexts". * These expanded contexts enable a number of new abilities, especially * "Execlists" (also implemented in this file). * + * One of the main differences with the legacy HW contexts is that logical + * ring contexts incorporate many more things to the context's state, like + * PDPs or ringbuffer control registers: + * + * The reason why PDPs are included in the context is straightforward: as + * PPGTTs (per-process GTTs) are actually per-context, having the PDPs + * contained there mean you don't need to do a ppgtt->switch_mm yourself, + * instead, the GPU will do it for you on the context switch. + * + * But, what about the ringbuffer control registers (head, tail, etc..)? + * shouldn't we just need a set of those per engine command streamer? This is + * where the name "Logical Rings" starts to make sense: by virtualizing the + * rings, the engine cs shifts to a new "ring buffer" with every context + * switch. When you want to submit a workload to the GPU you: A) choose your + * context, B) find its appropriate virtualized ring, C) write commands to it + * and then, finally, D) tell the GPU to switch to that context. + * + * Instead of the legacy MI_SET_CONTEXT, the way you tell the GPU to switch + * to a contexts is via a context execution list, ergo "Execlists". + * + * LRC implementation: + * Regarding the creation of contexts, we have: + * + * - One global default context. + * - One local default context for each opened fd. + * - One local extra context for each context create ioctl call. + * + * Now that ringbuffers belong per-context (and not per-engine, like before) + * and that contexts are uniquely tied to a given engine (and not reusable, + * like before) we need: + * + * - One ringbuffer per-engine inside each context. + * - One backing object per-engine inside each context. + * + * The global default context starts its life with these new objects fully + * allocated and populated. The local default context for each opened fd is + * more complex, because we don't know at creation time which engine is going + * to use them. To handle this, we have implemented a deferred creation of LR + * contexts: + * + * The local context starts its life as a hollow or blank holder, that only + * gets populated for a given engine once we receive an execbuffer. If later + * on we receive another execbuffer ioctl for the same context but a different + * engine, we allocate/populate a new ringbuffer and context backing object and + * so on. + * + * Finally, regarding local contexts created using the ioctl call: as they are + * only allowed with the render ring, we can allocate & populate them right + * away (no need to defer anything, at least for now). + * + * Execlists implementation: * Execlists are the new method by which, on gen8+ hardware, workloads are * submitted for execution (as opposed to the legacy, ringbuffer-based, method). + * This method works as follows: + * + * When a request is committed, its commands (the BB start and any leading or + * trailing commands, like the seqno breadcrumbs) are placed in the ringbuffer + * for the appropriate context. The tail pointer in the hardware context is not + * updated at this time, but instead, kept by the driver in the ringbuffer + * structure. A structure representing this request is added to a request queue + * for the appropriate engine: this structure contains a copy of the context's + * tail after the request was written to the ring buffer and a pointer to the + * context itself. + * + * If the engine's request queue was empty before the request was added, the + * queue is processed immediately. Otherwise the queue will be processed during + * a context switch interrupt. In any case, elements on the queue will get sent + * (in pairs) to the GPU's ExecLists Submit Port (ELSP, for short) with a + * globally unique 20-bits submission ID. + * + * When execution of a request completes, the GPU updates the context status + * buffer with a context complete event and generates a context switch interrupt. + * During the interrupt handling, the driver examines the events in the buffer: + * for each context complete event, if the announced ID matches that on the head + * of the request queue, then that request is retired and removed from the queue. + * + * After processing, if any requests were retired and the queue is not empty + * then a new execution list can be submitted. The two requests at the front of + * the queue are next to be submitted but since a context may not occur twice in + * an execution list, if subsequent requests have the same ID as the first then + * the two requests must be combined. This is done simply by discarding requests + * at the head of the queue until either only one requests is left (in which case + * we use a NULL second context) or the first two requests have unique IDs. + * + * By always executing the first two requests in the queue the driver ensures + * that the GPU is kept as busy as possible. In the case where a single context + * completes but a second context is still executing, the request for this second + * context will be at the head of the queue when we remove the first one. This + * request will then be resubmitted along with a new request for a different context, + * which will cause the hardware to continue executing the second request and queue + * the new request (the GPU detects the condition of a context getting preempted + * with the same context and optimizes the context switch flow by not doing + * preemption, but just sampling the new tail pointer). + * */ #include @@ -109,6 +204,17 @@ enum { }; #define GEN8_CTX_ID_SHIFT 32 +/** + * intel_sanitize_enable_execlists() - sanitize i915.enable_execlists + * @dev: DRM device. + * @enable_execlists: value of i915.enable_execlists module parameter. + * + * Only certain platforms support Execlists (the prerequisites being + * support for Logical Ring Contexts and Aliasing PPGTT or better), + * and only when enabled via module parameter. + * + * Return: 1 if Execlists is supported and has to be enabled. + */ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists) { WARN_ON(i915.enable_ppgtt == -1); @@ -123,6 +229,18 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists return 0; } +/** + * intel_execlists_ctx_id() - get the Execlists Context ID + * @ctx_obj: Logical Ring Context backing object. + * + * Do not confuse with ctx->id! Unfortunately we have a name overload + * here: the old context ID we pass to userspace as a handler so that + * they can refer to a context, and the new context ID we pass to the + * ELSP so that the GPU can inform us of the context status via + * interrupts. + * + * Return: 20-bits globally unique context ID. + */ u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj) { u32 lrca = i915_gem_obj_ggtt_offset(ctx_obj); @@ -313,6 +431,13 @@ static bool execlists_check_remove_request(struct intel_engine_cs *ring, return false; } +/** + * intel_execlists_handle_ctx_events() - handle Context Switch interrupts + * @ring: Engine Command Streamer to handle. + * + * Check the unread Context Status Buffers and manage the submission of new + * contexts to the ELSP accordingly. + */ void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring) { struct drm_i915_private *dev_priv = ring->dev->dev_private; @@ -481,6 +606,23 @@ static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf, return logical_ring_invalidate_all_caches(ringbuf); } +/** + * execlists_submission() - submit a batchbuffer for execution, Execlists style + * @dev: DRM device. + * @file: DRM file. + * @ring: Engine Command Streamer to submit to. + * @ctx: Context to employ for this submission. + * @args: execbuffer call arguments. + * @vmas: list of vmas. + * @batch_obj: the batchbuffer to submit. + * @exec_start: batchbuffer start virtual address pointer. + * @flags: translated execbuffer call flags. + * + * This is the evil twin version of i915_gem_ringbuffer_submission. It abstracts + * away the submission details of the execbuffer ioctl call. + * + * 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, @@ -608,6 +750,15 @@ int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf) return 0; } +/** + * intel_logical_ring_advance_and_submit() - advance the tail and submit the workload + * @ringbuf: Logical Ringbuffer to advance. + * + * 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 + * on a queue waiting for the ELSP to be ready to accept a new context submission. At that + * point, the tail *inside* the context is updated and the ELSP written to. + */ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf) { struct intel_engine_cs *ring = ringbuf->ring; @@ -781,6 +932,19 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, int bytes) return 0; } +/** + * intel_logical_ring_begin() - prepare the logical ringbuffer to accept some commands + * + * @ringbuf: Logical ringbuffer. + * @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 + * be wrapped, or wait a bit for the tail to be updated). This function takes care of that + * and also preallocates a request (every workload submission is still mediated through + * requests, same as it did with legacy ringbuffer submission). + * + * Return: non-zero if the ringbuffer is not ready to be written to. + */ int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords) { struct intel_engine_cs *ring = ringbuf->ring; @@ -1021,6 +1185,12 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf) return 0; } +/** + * intel_logical_ring_cleanup() - deallocate the Engine Command Streamer + * + * @ring: Engine Command Streamer. + * + */ void intel_logical_ring_cleanup(struct intel_engine_cs *ring) { struct drm_i915_private *dev_priv = ring->dev->dev_private; @@ -1215,6 +1385,16 @@ static int logical_vebox_ring_init(struct drm_device *dev) return logical_ring_init(dev, ring); } +/** + * intel_logical_rings_init() - allocate, populate and init the Engine Command Streamers + * @dev: DRM device. + * + * This function inits the engines for an Execlists submission style (the equivalent in the + * legacy ringbuffer submission world would be i915_gem_init_rings). It does it only for + * those engines that are present in the hardware. + * + * Return: non-zero if the initialization failed. + */ int intel_logical_rings_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1377,6 +1557,14 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o return 0; } +/** + * intel_lr_context_free() - free the LRC specific bits of a context + * @ctx: the LR context to free. + * + * The real context freeing is done in i915_gem_context_free: this only + * takes care of the bits that are LRC related: the per-engine backing + * objects and the logical ringbuffer. + */ void intel_lr_context_free(struct intel_context *ctx) { int i; @@ -1415,6 +1603,19 @@ static uint32_t get_lr_context_size(struct intel_engine_cs *ring) return ret; } +/** + * intel_lr_context_deferred_create() - create the LRC specific bits of a context + * @ctx: LR context to create. + * @ring: engine to be used with the context. + * + * This function can be called more than once, with different engines, if we plan + * to use the context with them. The context backing objects and the ringbuffers + * (specially the ringbuffer backing objects) suck a lot of memory up, and that's why + * the creation is a deferred call: it's better to make sure first that we need to use + * a given ring with the context. + * + * Return: non-zero on eror. + */ int intel_lr_context_deferred_create(struct intel_context *ctx, struct intel_engine_cs *ring) { diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 117d1a4eb3b9..991d4499fb03 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -38,10 +38,21 @@ int intel_logical_rings_init(struct drm_device *dev); int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf); void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf); +/** + * intel_logical_ring_advance() - advance the ringbuffer tail + * @ringbuf: Ringbuffer to advance. + * + * The tail is only updated in our logical ringbuffer struct. + */ static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf) { ringbuf->tail &= ringbuf->size - 1; } +/** + * intel_logical_ring_emit() - write a DWORD to the ringbuffer. + * @ringbuf: Ringbuffer to write to. + * @data: DWORD to write. + */ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf, u32 data) { @@ -66,6 +77,25 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, u64 exec_start, u32 flags); u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj); +/** + * struct intel_ctx_submit_request - queued context submission request + * @ctx: Context to submit to the ELSP. + * @ring: Engine to submit it to. + * @tail: how far in the context's ringbuffer this request goes to. + * @execlist_link: link in the submission queue. + * @work: workqueue for processing this request in a bottom half. + * @elsp_submitted: no. of times this request has been sent to the ELSP. + * + * The ELSP only accepts two elements at a time, so we queue context/tail + * pairs on a given queue (ring->execlist_queue) until the hardware is + * available. The queue serves a double purpose: we also use it to keep track + * of the up to 2 contexts currently in the hardware (usually one in execution + * and the other queued up by the GPU): We only remove elements from the head + * of the queue when the hardware informs us that an element has been + * completed. + * + * All accesses to the queue are mediated by a spinlock (ring->execlist_lock). + */ struct intel_ctx_submit_request { struct intel_context *ctx; struct intel_engine_cs *ring; -- GitLab From d7f621e50704306c348ccb192f17047f1499f9bc Mon Sep 17 00:00:00 2001 From: Oscar Mateo Date: Thu, 24 Jul 2014 17:04:49 +0100 Subject: [PATCH 0467/5088] drm/i915/bdw: Enable Logical Ring Contexts (hence, Execlists) The time has come, the Walrus said, to talk of many things. Signed-off-by: Oscar Mateo Reviewed-by: Damien Lespiau 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 ed52ac744105..d4d2abbb8e6c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2088,7 +2088,7 @@ struct drm_i915_cmd_table { #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) #define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 6) -#define HAS_LOGICAL_RING_CONTEXTS(dev) 0 +#define HAS_LOGICAL_RING_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 8) #define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_PPGTT(dev) (INTEL_INFO(dev)->gen >= 7 && !IS_GEN8(dev)) #define USES_PPGTT(dev) (i915.enable_ppgtt) -- GitLab From fd639ac6dcbcbae4f2131bf1390a032df659ffb7 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 15 Aug 2014 16:48:36 +0100 Subject: [PATCH 0468/5088] drm/i915/bdw: Disable execlists by default We still have a few missing bits and pieces to have execlists enabled by default eg. the error capture or the render state initialization and so it wouldn't be wise to enable it by default on BDW just yet. Cc: Daniel Vetter Cc: Thomas Daniel Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Tested-by: Paulo Zanoni Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=82740 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_params.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index f7f8350c3793..1dcb1bed5ef8 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -35,7 +35,7 @@ struct i915_params i915 __read_mostly = { .vbt_sdvo_panel_type = -1, .enable_rc6 = -1, .enable_fbc = -1, - .enable_execlists = -1, + .enable_execlists = 0, .enable_hangcheck = true, .enable_ppgtt = -1, .enable_psr = 1, @@ -122,7 +122,7 @@ MODULE_PARM_DESC(enable_ppgtt, module_param_named(enable_execlists, i915.enable_execlists, int, 0400); MODULE_PARM_DESC(enable_execlists, "Override execlists usage. " - "(-1=auto [default], 0=disabled, 1=enabled)"); + "(-1=auto, 0=disabled [default], 1=enabled)"); module_param_named(enable_psr, i915.enable_psr, int, 0600); MODULE_PARM_DESC(enable_psr, "Enable PSR (default: true)"); -- GitLab From 3a5f87c286515c54ff5c52c3e64d0c522b7570c0 Mon Sep 17 00:00:00 2001 From: Thomas Wood Date: Wed, 20 Aug 2014 14:45:00 +0100 Subject: [PATCH 0469/5088] drm: fix plane rotation when restoring fbdev configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure plane rotation is reset correctly when restoring the fbdev configuration by using drm_mode_plane_set_obj_prop which calls the driver's set_property callback. The rotation reset feature was introduced in commit 9783de2 (drm: Resetting rotation property) and the callback issue was originally addressed in a previous version of the patch, but the fix was not present in the final version. v2: Fix documentation warning Add some more details to the commit message (Daniel Vetter) Testcase: igt/kms_rotation_crc Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=82236 Cc: Sonika Jindal Cc: Ville Syrjälä Cc: Dave Airlie Cc: Daniel Vetter Signed-off-by: Thomas Wood Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 25 ++++++++++++++++++++----- drivers/gpu/drm/drm_fb_helper.c | 6 +++--- include/drm/drm_crtc.h | 3 +++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3c4a62169f28..d7e4c0e2e796 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4156,12 +4156,25 @@ static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, return ret; } -static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t value) +/** + * drm_mode_plane_set_obj_prop - set the value of a property + * @plane: drm plane object to set property value for + * @property: property to set + * @value: value the property should be set to + * + * This functions sets a given property on a given plane object. This function + * calls the driver's ->set_property callback and changes the software state of + * the property if the callback succeeds. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_mode_plane_set_obj_prop(struct drm_plane *plane, + struct drm_property *property, + uint64_t value) { int ret = -EINVAL; - struct drm_plane *plane = obj_to_plane(obj); + struct drm_mode_object *obj = &plane->base; if (plane->funcs->set_property) ret = plane->funcs->set_property(plane, property, value); @@ -4170,6 +4183,7 @@ static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj, return ret; } +EXPORT_SYMBOL(drm_mode_plane_set_obj_prop); /** * drm_mode_getproperty_ioctl - get the current value of a object's property @@ -4308,7 +4322,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value); break; case DRM_MODE_OBJECT_PLANE: - ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value); + ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj), + property, arg->value); break; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d139eddb3d61..99569ee5adee 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -350,9 +350,9 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) drm_plane_force_disable(plane); if (dev->mode_config.rotation_property) { - drm_object_property_set_value(&plane->base, - dev->mode_config.rotation_property, - BIT(DRM_ROTATE_0)); + drm_mode_plane_set_obj_prop(plane, + dev->mode_config.rotation_property, + BIT(DRM_ROTATE_0)); } } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 62f73bdbcc47..38fae5d9ad73 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1121,6 +1121,9 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane, + struct drm_property *property, + uint64_t value); extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); -- GitLab From 448466b723cc7b44016547116aa2b55a3736f1f0 Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Mon, 19 May 2014 11:50:24 -0600 Subject: [PATCH 0470/5088] x86: Remove obsolete comment in uapi/e820.h A comment introduced by this old commit: 028b785888c5 ("x86 boot: extend some internal memory map arrays to handle larger EFI input") had to do with some nested preprocessor directives. The directives were split into separate files by this commit: af170c5061dd ("UAPI: (Scripted) Disintegrate arch/x86/include/asm") The comment explaining their interaction was retained and is now present in arch/x86/include/uapi/asm/e820.h. This comment is no longer correct, so delete it. Signed-off-by: Ross Zwisler Link: http://lkml.kernel.org/r/1400521824-21040-1-git-send-email-ross.zwisler@linux.intel.com Signed-off-by: Ingo Molnar --- arch/x86/include/uapi/asm/e820.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/x86/include/uapi/asm/e820.h b/arch/x86/include/uapi/asm/e820.h index bbae02470701..d993e33f5236 100644 --- a/arch/x86/include/uapi/asm/e820.h +++ b/arch/x86/include/uapi/asm/e820.h @@ -21,11 +21,6 @@ * this size. */ -/* - * Odd: 'make headers_check' complains about numa.h if I try - * to collapse the next two #ifdef lines to a single line: - * #if defined(__KERNEL__) && defined(CONFIG_EFI) - */ #ifndef __KERNEL__ #define E820_X_MAX E820MAX #endif -- GitLab From 1c36d42c4ffee9e38e122ed822dd0a545a3a86da Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 20 Aug 2014 16:49:32 +0200 Subject: [PATCH 0471/5088] irqchip: renesas-intc-irqpin: Add suspend-to-RAM wake up support Set the ->irq_enable() and ->irq_disable() methods to NULL to enable lazy disable of interrupts, and set IRQCHIP_MASK_ON_SUSPEND to tell the core that only IRQs marked as wake-ups need to stay enabled during suspend-to-RAM. This makes wake-up by gpio-keys from suspend-to-RAM work on r8a7740/Armadillo. Signed-off-by: Geert Uytterhoeven Link: https://lkml.kernel.org/r/1408546172-22484-1-git-send-email-geert+renesas@glider.be Signed-off-by: Jason Cooper --- drivers/irqchip/irq-renesas-intc-irqpin.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index 3ee78f02e5d7..a9efceb0c4a0 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -454,10 +454,8 @@ static int intc_irqpin_probe(struct platform_device *pdev) irq_chip->name = name; irq_chip->irq_mask = disable_fn; irq_chip->irq_unmask = enable_fn; - irq_chip->irq_enable = enable_fn; - irq_chip->irq_disable = disable_fn; irq_chip->irq_set_type = intc_irqpin_irq_set_type; - irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; + irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, p->number_of_irqs, -- GitLab From f5885f40976bc8c8cb8fa17616ccc423f6daae04 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Aug 2014 13:10:24 -0300 Subject: [PATCH 0472/5088] [media] au0828: no need to sleep at the IR code This sleep was doing some debouncing on the original driver. This is not needed on Linux, because the RC core and the input layer already takes care of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index fd0d3a90ce7d..39ddf3c4fdfe 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -135,8 +135,6 @@ static int au0828_get_key_au8522(struct au0828_rc *ir) /* Disable IR */ au8522_rc_clear(ir, 0xe0, 1 << 4); - usleep_range(45000, 46000); - /* Enable IR */ au8522_rc_set(ir, 0xe0, 1 << 4); -- GitLab From ff346b0f5d86688baf7c191faf192e69cf347583 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Aug 2014 13:10:25 -0300 Subject: [PATCH 0473/5088] [media] au0828: add an option to disable IR via modprobe parameter The IR code increases the power consumption of the device. Allow to disable it via modprobe parameter. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 39ddf3c4fdfe..590f99d02c93 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -25,6 +25,10 @@ #include #include +static int disable_ir; +module_param(disable_ir, int, 0444); +MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); + #include "au0828.h" struct au0828_rc { @@ -271,7 +275,7 @@ int au0828_rc_register(struct au0828_dev *dev) int err = -ENOMEM; u16 i2c_rc_dev_addr = 0; - if (!dev->board.has_ir_i2c) + if (!dev->board.has_ir_i2c || disable_ir) return 0; i2c_rc_dev_addr = au0828_probe_i2c_ir(dev); -- GitLab From d84fdc774b3beea1a7c601ff6e8d22e6ac13dd01 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Aug 2014 13:10:26 -0300 Subject: [PATCH 0474/5088] [media] au0828: Enable IR for HVR-850 HVR-850 also has a remote. Enable it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-cards.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index 2c6b7da137ed..b6c9d1f466bd 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -46,6 +46,7 @@ struct au0828_board au0828_boards[] = { .name = "Hauppauge HVR850", .tuner_type = TUNER_XC5000, .tuner_addr = 0x61, + .has_ir_i2c = 1, .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, .input = { { -- GitLab From 2e0cc7ee75a218ad43b112164e87acb03f0fd9f0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Aug 2014 10:46:30 -0300 Subject: [PATCH 0475/5088] [media] au0828-input: Be sure that IR is enabled at polling When the DVB code sets the frontend, it disables the IR INT, probably due to some hardware bug, as there's no code there at au8522 frontend that writes on register 0xe0. Fixing it at au8522 code is hard, as it doesn't know if the IR is enabled or disabled, and just restoring the value of register 0xe0 could cause other nasty effects. So, better to add a hack at au0828-input polling interval to enable int, if disabled. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 590f99d02c93..f0c5672e5f56 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -94,14 +94,19 @@ static int au8522_rc_read(struct au0828_rc *ir, u16 reg, int val, static int au8522_rc_andor(struct au0828_rc *ir, u16 reg, u8 mask, u8 value) { int rc; - char buf; + char buf, oldbuf; rc = au8522_rc_read(ir, reg, -1, &buf, 1); if (rc < 0) return rc; + oldbuf = buf; buf = (buf & ~mask) | (value & mask); + /* Nothing to do, just return */ + if (buf == oldbuf) + return 0; + return au8522_rc_write(ir, reg, buf); } @@ -126,8 +131,11 @@ static int au0828_get_key_au8522(struct au0828_rc *ir) /* Check IR int */ rc = au8522_rc_read(ir, 0xe1, -1, buf, 1); - if (rc < 0 || !(buf[0] & (1 << 4))) + if (rc < 0 || !(buf[0] & (1 << 4))) { + /* Be sure that IR is enabled */ + au8522_rc_set(ir, 0xe0, 1 << 4); return 0; + } /* Something arrived. Get the data */ rc = au8522_rc_read(ir, 0xe3, 0x11, buf, sizeof(buf)); -- GitLab From e9018af0b8897b02dc8e83e6cd75391afcadf894 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:07 -0300 Subject: [PATCH 0476/5088] [media] au0828: avoid race conditions at RC stop As the RC kthread can re-enable IR int, we should first cancel the kthread and then disable IR int. While here, remove a temporary debug printk. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index f0c5672e5f56..47ef07a693af 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -253,10 +253,10 @@ static void au0828_rc_stop(struct rc_dev *rc) { struct au0828_rc *ir = rc->priv; + cancel_delayed_work_sync(&ir->work); + /* Disable IR */ au8522_rc_clear(ir, 0xe0, 1 << 4); - - cancel_delayed_work_sync(&ir->work); } static int au0828_probe_i2c_ir(struct au0828_dev *dev) -- GitLab From 345e3bfdadf4ae12df6251d4bcb6b9fb48037690 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:08 -0300 Subject: [PATCH 0477/5088] [media] au0828: handle IR int during suspend/resume It doesn't make sense to handle an IR code given before suspending after the device resume. So, turn off IR int while suspending. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 47ef07a693af..7a5437a4d938 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -380,6 +380,9 @@ int au0828_rc_suspend(struct au0828_dev *dev) cancel_delayed_work_sync(&ir->work); + /* Disable IR */ + au8522_rc_clear(ir, 0xe0, 1 << 4); + return 0; } @@ -390,6 +393,9 @@ int au0828_rc_resume(struct au0828_dev *dev) if (!ir) return 0; + /* Enable IR */ + au8522_rc_set(ir, 0xe0, 1 << 4); + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); return 0; -- GitLab From 917cbcde46adf3e155ec61d92f6f29a4eb3acad1 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 8 Aug 2014 21:36:18 -0300 Subject: [PATCH 0478/5088] [media] au0828: add au0828_rc_*() stubs for VIDEO_AU0828_RC disabled case Define au0828_rc_*() stubs to avoid compile errors when VIDEO_AU0828_RC is disabled and avoid the need to enclose au0828_rc_*() in ifdef CONFIG_VIDEO_AU0828_RC in .c files. Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 96bec05d7dac..fd0916e20323 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -326,7 +326,14 @@ extern struct videobuf_queue_ops au0828_vbi_qops; } while (0) /* au0828-input.c */ -int au0828_rc_register(struct au0828_dev *dev); -void au0828_rc_unregister(struct au0828_dev *dev); -int au0828_rc_suspend(struct au0828_dev *dev); -int au0828_rc_resume(struct au0828_dev *dev); +#ifdef CONFIG_VIDEO_AU0828_RC +extern int au0828_rc_register(struct au0828_dev *dev); +extern void au0828_rc_unregister(struct au0828_dev *dev); +extern int au0828_rc_suspend(struct au0828_dev *dev); +extern int au0828_rc_resume(struct au0828_dev *dev); +#else +static inline int au0828_rc_register(struct au0828_dev *dev) { return 0; } +static inline void au0828_rc_unregister(struct au0828_dev *dev) { } +static inline int au0828_rc_suspend(struct au0828_dev *dev) { return 0; } +static inline int au0828_rc_resume(struct au0828_dev *dev) { return 0; } +#endif -- GitLab From 92143f6fb0d6655391b1b42f54ab94d3f16c00ac Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Sat, 9 Aug 2014 21:47:10 -0300 Subject: [PATCH 0479/5088] [media] au0828: remove CONFIG_VIDEO_AU0828_RC scope around au0828_rc_*() Remove CONFIG_VIDEO_AU0828_RC scope around au0828_rc_register() and au0828_rc_unregister() calls in au0828-core Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 56025e689442..b08b979bb9a7 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -153,9 +153,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface) dprintk(1, "%s()\n", __func__); -#ifdef CONFIG_VIDEO_AU0828_RC au0828_rc_unregister(dev); -#endif /* Digital TV */ au0828_dvb_unregister(dev); @@ -266,10 +264,8 @@ static int au0828_usb_probe(struct usb_interface *interface, pr_err("%s() au0282_dev_register failed\n", __func__); -#ifdef CONFIG_VIDEO_AU0828_RC /* Remote controller */ au0828_rc_register(dev); -#endif /* * Store the pointer to the au0828_dev so it can be accessed in -- GitLab From aaeac1991b2c3dff46e0aae5e1d7c7f46ac9eddc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:11 -0300 Subject: [PATCH 0480/5088] [media] au0828: don't let the IR polling thread to run at suspend Trying to make au0828 to suspend can do very bad things, as the polling Kthread is not handled. We should disable it during suspend, only re-enabling it at resume. Still, analog and digital TV won't work, as we don't reinit the settings at resume, but at least it won't hang. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 33 ++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index b08b979bb9a7..3a02de142f9f 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -281,13 +281,42 @@ static int au0828_usb_probe(struct usb_interface *interface, return retval; } +static int au0828_suspend(struct usb_interface *interface, + pm_message_t message) +{ + struct au0828_dev *dev = usb_get_intfdata(interface); + + if (!dev) + return 0; + + au0828_rc_suspend(dev); + + /* FIXME: should suspend also ATV/DTV */ + + return 0; +} + +static int au0828_resume(struct usb_interface *interface) +{ + struct au0828_dev *dev = usb_get_intfdata(interface); + if (!dev) + return 0; + + au0828_rc_resume(dev); + + /* FIXME: should resume also ATV/DTV */ + + return 0; +} + static struct usb_driver au0828_usb_driver = { .name = DRIVER_NAME, .probe = au0828_usb_probe, .disconnect = au0828_usb_disconnect, .id_table = au0828_usb_id_table, - - /* FIXME: Add suspend and resume functions */ + .suspend = au0828_suspend, + .resume = au0828_resume, + .reset_resume = au0828_resume, }; static int __init au0828_init(void) -- GitLab From fa500461db5af83fce7b1bd45e4925efadbebd90 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:12 -0300 Subject: [PATCH 0481/5088] [media] au0828: be sure to reenable the bridge and GPIOs on resume At resume, we should restore the register contents. So, reenable the bridge and GPIO settings. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 3a02de142f9f..87340a8af7d7 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -302,6 +302,12 @@ static int au0828_resume(struct usb_interface *interface) if (!dev) return 0; + /* Power Up the bridge */ + au0828_write(dev, REG_600, 1 << 4); + + /* Bring up the GPIO's and supporting devices */ + au0828_gpio_setup(dev); + au0828_rc_resume(dev); /* FIXME: should resume also ATV/DTV */ -- GitLab From b799de75e032c4d27788af9b4df3ab25858f87a8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:13 -0300 Subject: [PATCH 0482/5088] [media] au0828: Add suspend code for DVB The scheduled work should be cancelled during suspend. At resume time, we need to set the frontend again. So, add such logic to the driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 2 ++ drivers/media/usb/au0828/au0828-dvb.c | 31 +++++++++++++++++++++++++- drivers/media/usb/au0828/au0828.h | 2 ++ 3 files changed, 34 insertions(+), 1 deletion(-) mode change 100644 => 100755 drivers/media/usb/au0828/au0828-dvb.c diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 87340a8af7d7..26ec50539dc4 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -290,6 +290,7 @@ static int au0828_suspend(struct usb_interface *interface, return 0; au0828_rc_suspend(dev); + au0828_dvb_suspend(dev); /* FIXME: should suspend also ATV/DTV */ @@ -309,6 +310,7 @@ static int au0828_resume(struct usb_interface *interface) au0828_gpio_setup(dev); au0828_rc_resume(dev); + au0828_dvb_resume(dev); /* FIXME: should resume also ATV/DTV */ diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c old mode 100644 new mode 100755 index d8b5d9480279..7b6e71065aa4 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -618,3 +617,33 @@ int au0828_dvb_register(struct au0828_dev *dev) return 0; } + +void au0828_dvb_suspend(struct au0828_dev *dev) +{ + struct au0828_dvb *dvb = &dev->dvb; + + if (dvb && dev->urb_streaming) { + cancel_work_sync(&dev->restart_streaming); + + /* Stop transport */ + mutex_lock(&dvb->lock); + stop_urb_transfer(dev); + au0828_stop_transport(dev, 1); + mutex_unlock(&dvb->lock); + } +} + +void au0828_dvb_resume(struct au0828_dev *dev) +{ + struct au0828_dvb *dvb = &dev->dvb; + + if (dvb && dev->urb_streaming) { + au0828_set_frontend(dvb->frontend); + + /* Start transport */ + mutex_lock(&dvb->lock); + au0828_start_transport(dev); + start_urb_transfer(dev); + mutex_unlock(&dvb->lock); + } +} diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index fd0916e20323..d32234353096 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -316,6 +316,8 @@ void au0828_analog_unregister(struct au0828_dev *dev); /* au0828-dvb.c */ extern int au0828_dvb_register(struct au0828_dev *dev); extern void au0828_dvb_unregister(struct au0828_dev *dev); +void au0828_dvb_suspend(struct au0828_dev *dev); +void au0828_dvb_resume(struct au0828_dev *dev); /* au0828-vbi.c */ extern struct videobuf_queue_ops au0828_vbi_qops; -- GitLab From e2147d0af0aa77c1a7b610224161993ef62e3ac1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:14 -0300 Subject: [PATCH 0483/5088] [media] au0828: properly handle stream on/off state The STREAM_ON state is used by s_format callback, but the driver never sets it. Fix it. This will also be needed in order to handle suspend/resume ops. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 98f7ea1d6d63..36ff3b496f87 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -159,6 +159,7 @@ static void au0828_irq_callback(struct urb *urb) au0828_isocdbg("urb resubmit failed (error=%i)\n", urb->status); } + dev->stream_state = STREAM_ON; } /* @@ -198,6 +199,8 @@ static void au0828_uninit_isoc(struct au0828_dev *dev) dev->isoc_ctl.urb = NULL; dev->isoc_ctl.transfer_buffer = NULL; dev->isoc_ctl.num_bufs = 0; + + dev->stream_state = STREAM_OFF; } /* -- GitLab From 1a1ba95e80e567176aeb2a10b2dc6d920b06a33e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:15 -0300 Subject: [PATCH 0484/5088] [media] au0828: add suspend/resume code for V4L2 No timers should be enabled during suspend. So, stop them. At resume time, we should do the proper initialization for it to keep working. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 2 + drivers/media/usb/au0828/au0828-video.c | 59 ++++++++++++++++++++++++- drivers/media/usb/au0828/au0828.h | 7 +++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 26ec50539dc4..5f13888d73a0 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -290,6 +290,7 @@ static int au0828_suspend(struct usb_interface *interface, return 0; au0828_rc_suspend(dev); + au0828_v4l2_suspend(dev); au0828_dvb_suspend(dev); /* FIXME: should suspend also ATV/DTV */ @@ -310,6 +311,7 @@ static int au0828_resume(struct usb_interface *interface) au0828_gpio_setup(dev); au0828_rc_resume(dev); + au0828_v4l2_resume(dev); au0828_dvb_resume(dev); /* FIXME: should resume also ATV/DTV */ diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 36ff3b496f87..574a08c7013d 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -1871,6 +1870,64 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) return rc; } +void au0828_v4l2_suspend(struct au0828_dev *dev) +{ + struct urb *urb; + int i; + + if (dev->stream_state == STREAM_ON) { + au0828_analog_stream_disable(dev); + /* stop urbs */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = dev->isoc_ctl.urb[i]; + if (urb) { + if (!irqs_disabled()) + usb_kill_urb(urb); + else + usb_unlink_urb(urb); + } + } + } + + if (dev->vid_timeout_running) + del_timer_sync(&dev->vid_timeout); + if (dev->vbi_timeout_running) + del_timer_sync(&dev->vbi_timeout); +} + +void au0828_v4l2_resume(struct au0828_dev *dev) +{ + int i, rc; + + if (dev->stream_state == STREAM_ON) { + au0828_stream_interrupt(dev); + au0828_init_tuner(dev); + } + + if (dev->vid_timeout_running) + mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); + if (dev->vbi_timeout_running) + mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); + + /* If we were doing ac97 instead of i2s, it would go here...*/ + au0828_i2s_init(dev); + + au0828_analog_stream_enable(dev); + + if (!(dev->stream_state == STREAM_ON)) { + au0828_analog_stream_reset(dev); + /* submit urbs */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); + if (rc) { + au0828_isocdbg("submit of urb %i failed (error=%i)\n", + i, rc); + au0828_uninit_isoc(dev); + } + } + } +} + static struct v4l2_file_operations au0828_v4l_fops = { .owner = THIS_MODULE, .open = au0828_v4l2_open, diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index d32234353096..0d8cfe5cd264 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -311,6 +311,13 @@ int au0828_analog_register(struct au0828_dev *dev, struct usb_interface *interface); int au0828_analog_stream_disable(struct au0828_dev *d); void au0828_analog_unregister(struct au0828_dev *dev); +#ifdef CONFIG_VIDEO_AU0828_V4L2 +void au0828_v4l2_suspend(struct au0828_dev *dev); +void au0828_v4l2_resume(struct au0828_dev *dev); +#else +static inline void au0828_v4l2_suspend(struct au0828_dev *dev) { }; +static inline void au0828_v4l2_resume(struct au0828_dev *dev) { }; +#endif /* ----------------------------------------------------------- */ /* au0828-dvb.c */ -- GitLab From 3d8de92e07b855d22e9807a287f80ee910331d51 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:16 -0300 Subject: [PATCH 0485/5088] [media] au0828: Remove a bad whitespace Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 7a5437a4d938..5efb83977f39 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -133,7 +133,7 @@ static int au0828_get_key_au8522(struct au0828_rc *ir) rc = au8522_rc_read(ir, 0xe1, -1, buf, 1); if (rc < 0 || !(buf[0] & (1 << 4))) { /* Be sure that IR is enabled */ - au8522_rc_set(ir, 0xe0, 1 << 4); + au8522_rc_set(ir, 0xe0, 1 << 4); return 0; } -- GitLab From 83afb32aa9d8cc77049c0e4e124e3bed8b88428f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:17 -0300 Subject: [PATCH 0486/5088] [media] au0828: use pr_foo macros Instead of using printk(KERN_foo, use pr_foo() macros. No functional changes. Note: we should do the same for dprintk(), but that would require to remove the dprintk levels. So, for now, let's not touch on it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-cards.c | 13 +++---- drivers/media/usb/au0828/au0828-core.c | 33 ++++++++-------- drivers/media/usb/au0828/au0828-dvb.c | 50 ++++++++++++------------- drivers/media/usb/au0828/au0828-i2c.c | 15 ++++---- drivers/media/usb/au0828/au0828-input.c | 4 +- drivers/media/usb/au0828/au0828-vbi.c | 4 +- drivers/media/usb/au0828/au0828-video.c | 23 ++++++------ drivers/media/usb/au0828/au0828.h | 5 ++- 8 files changed, 72 insertions(+), 75 deletions(-) mode change 100755 => 100644 drivers/media/usb/au0828/au0828-dvb.c diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index b6c9d1f466bd..d229c6dbddb9 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -143,8 +143,7 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg) mdelay(10); return 0; } else { - printk(KERN_ERR - "%s(): Unknown command.\n", __func__); + pr_err("%s(): Unknown command.\n", __func__); return -EINVAL; } break; @@ -178,12 +177,12 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data) case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */ break; default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", __func__, tv.model); + pr_warn("%s: warning: unknown hauppauge model #%d\n", + __func__, tv.model); break; } - printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + pr_info("%s: hauppauge eeprom: model=%d\n", __func__, tv.model); } @@ -229,7 +228,7 @@ void au0828_card_analog_fe_setup(struct au0828_dev *dev) sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, "au8522", 0x8e >> 1, NULL); if (sd == NULL) - printk(KERN_ERR "analog subdev registration failed\n"); + pr_err("analog subdev registration failed\n"); } /* Setup tuners */ @@ -238,7 +237,7 @@ void au0828_card_analog_fe_setup(struct au0828_dev *dev) sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, "tuner", dev->board.tuner_addr, NULL); if (sd == NULL) - printk(KERN_ERR "tuner subdev registration fail\n"); + pr_err("tuner subdev registration fail\n"); tun_setup.mode_mask = mode_mask; tun_setup.type = dev->board.tuner_type; diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 5f13888d73a0..452d14249348 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -19,14 +19,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "au0828.h" + #include #include #include #include #include -#include "au0828.h" - /* * 1 = General debug messages * 2 = USB handling @@ -90,7 +90,7 @@ static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value, status = min(status, 0); if (status < 0) { - printk(KERN_ERR "%s() Failed sending control message, error %d.\n", + pr_err("%s() Failed sending control message, error %d.\n", __func__, status); } @@ -115,7 +115,7 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, status = min(status, 0); if (status < 0) { - printk(KERN_ERR "%s() Failed receiving control message, error %d.\n", + pr_err("%s() Failed receiving control message, error %d.\n", __func__, status); } @@ -197,15 +197,14 @@ static int au0828_usb_probe(struct usb_interface *interface, * not enough even for most Digital TV streams. */ if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { - printk(KERN_ERR "au0828: Device initialization failed.\n"); - printk(KERN_ERR "au0828: Device must be connected to a " - "high-speed USB 2.0 port.\n"); + pr_err("au0828: Device initialization failed.\n"); + pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n"); return -ENODEV; } dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - printk(KERN_ERR "%s() Unable to allocate memory\n", __func__); + pr_err("%s() Unable to allocate memory\n", __func__); return -ENOMEM; } @@ -273,7 +272,7 @@ static int au0828_usb_probe(struct usb_interface *interface, */ usb_set_intfdata(interface, dev); - printk(KERN_INFO "Registered device AU0828 [%s]\n", + pr_info("Registered device AU0828 [%s]\n", dev->board.name == NULL ? "Unset" : dev->board.name); mutex_unlock(&dev->lock); @@ -320,7 +319,7 @@ static int au0828_resume(struct usb_interface *interface) } static struct usb_driver au0828_usb_driver = { - .name = DRIVER_NAME, + .name = KBUILD_MODNAME, .probe = au0828_usb_probe, .disconnect = au0828_usb_disconnect, .id_table = au0828_usb_id_table, @@ -334,27 +333,27 @@ static int __init au0828_init(void) int ret; if (au0828_debug & 1) - printk(KERN_INFO "%s() Debugging is enabled\n", __func__); + pr_info("%s() Debugging is enabled\n", __func__); if (au0828_debug & 2) - printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__); + pr_info("%s() USB Debugging is enabled\n", __func__); if (au0828_debug & 4) - printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__); + pr_info("%s() I2C Debugging is enabled\n", __func__); if (au0828_debug & 8) - printk(KERN_INFO "%s() Bridge Debugging is enabled\n", + pr_info("%s() Bridge Debugging is enabled\n", __func__); if (au0828_debug & 16) - printk(KERN_INFO "%s() IR Debugging is enabled\n", + pr_info("%s() IR Debugging is enabled\n", __func__); - printk(KERN_INFO "au0828 driver loaded\n"); + pr_info("au0828 driver loaded\n"); ret = usb_register(&au0828_usb_driver); if (ret) - printk(KERN_ERR "usb_register failed, error = %d\n", ret); + pr_err("usb_register failed, error = %d\n", ret); return ret; } diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c old mode 100755 new mode 100644 index 7b6e71065aa4..99cf83bca033 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "au0828.h" + #include #include #include @@ -26,7 +28,6 @@ #include #include -#include "au0828.h" #include "au8522.h" #include "xc5000.h" #include "mxl5007t.h" @@ -126,7 +127,7 @@ static void urb_completion(struct urb *purb) } if (ptype != PIPE_BULK) { - printk(KERN_ERR "%s: Unsupported URB type %d\n", + pr_err("%s: Unsupported URB type %d\n", __func__, ptype); return; } @@ -201,8 +202,7 @@ static int start_urb_transfer(struct au0828_dev *dev) if (!purb->transfer_buffer) { usb_free_urb(purb); dev->urbs[i] = NULL; - printk(KERN_ERR - "%s: failed big buffer allocation, err = %d\n", + pr_err("%s: failed big buffer allocation, err = %d\n", __func__, ret); goto err; } @@ -223,8 +223,8 @@ static int start_urb_transfer(struct au0828_dev *dev) ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC); if (ret != 0) { stop_urb_transfer(dev); - printk(KERN_ERR "%s: failed urb submission, " - "err = %d\n", __func__, ret); + pr_err("%s: failed urb submission, err = %d\n", + __func__, ret); return ret; } } @@ -392,9 +392,8 @@ static int dvb_register(struct au0828_dev *dev) if (!dev->dig_transfer_buffer[i]) { result = -ENOMEM; - printk(KERN_ERR - "%s: failed buffer allocation (errno = %d)\n", - DRIVER_NAME, result); + pr_err("failed buffer allocation (errno = %d)\n", + result); goto fail_adapter; } } @@ -403,11 +402,12 @@ static int dvb_register(struct au0828_dev *dev) INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming); /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, + result = dvb_register_adapter(&dvb->adapter, + KBUILD_MODNAME, THIS_MODULE, &dev->usbdev->dev, adapter_nr); if (result < 0) { - printk(KERN_ERR "%s: dvb_register_adapter failed " - "(errno = %d)\n", DRIVER_NAME, result); + pr_err("dvb_register_adapter failed (errno = %d)\n", + result); goto fail_adapter; } dvb->adapter.priv = dev; @@ -415,8 +415,8 @@ static int dvb_register(struct au0828_dev *dev) /* register frontend */ result = dvb_register_frontend(&dvb->adapter, dvb->frontend); if (result < 0) { - printk(KERN_ERR "%s: dvb_register_frontend failed " - "(errno = %d)\n", DRIVER_NAME, result); + pr_err("dvb_register_frontend failed (errno = %d)\n", + result); goto fail_frontend; } @@ -435,8 +435,7 @@ static int dvb_register(struct au0828_dev *dev) dvb->demux.stop_feed = au0828_dvb_stop_feed; result = dvb_dmx_init(&dvb->demux); if (result < 0) { - printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n", - DRIVER_NAME, result); + pr_err("dvb_dmx_init failed (errno = %d)\n", result); goto fail_dmx; } @@ -445,31 +444,29 @@ static int dvb_register(struct au0828_dev *dev) dvb->dmxdev.capabilities = 0; result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); if (result < 0) { - printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n", - DRIVER_NAME, result); + pr_err("dvb_dmxdev_init failed (errno = %d)\n", result); goto fail_dmxdev; } dvb->fe_hw.source = DMX_FRONTEND_0; result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); if (result < 0) { - printk(KERN_ERR "%s: add_frontend failed " - "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result); + pr_err("add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", + result); goto fail_fe_hw; } dvb->fe_mem.source = DMX_MEMORY_FE; result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); if (result < 0) { - printk(KERN_ERR "%s: add_frontend failed " - "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result); + pr_err("add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", + result); goto fail_fe_mem; } result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); if (result < 0) { - printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n", - DRIVER_NAME, result); + pr_err("connect_frontend failed (errno = %d)\n", result); goto fail_fe_conn; } @@ -595,12 +592,11 @@ int au0828_dvb_register(struct au0828_dev *dev) } break; default: - printk(KERN_WARNING "The frontend of your DVB/ATSC card " - "isn't supported yet\n"); + pr_warn("The frontend of your DVB/ATSC card isn't supported yet\n"); break; } if (NULL == dvb->frontend) { - printk(KERN_ERR "%s() Frontend initialization failed\n", + pr_err("%s() Frontend initialization failed\n", __func__); return -1; } diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c index daaeaf1b089c..ae7ac6669769 100644 --- a/drivers/media/usb/au0828/au0828-i2c.c +++ b/drivers/media/usb/au0828/au0828-i2c.c @@ -19,13 +19,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "au0828.h" + #include #include #include #include #include -#include "au0828.h" #include "media/tuner.h" #include @@ -340,7 +341,7 @@ static struct i2c_algorithm au0828_i2c_algo_template = { /* ----------------------------------------------------------------------- */ static struct i2c_adapter au0828_i2c_adap_template = { - .name = DRIVER_NAME, + .name = KBUILD_MODNAME, .owner = THIS_MODULE, .algo = &au0828_i2c_algo_template, }; @@ -365,7 +366,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) rc = i2c_master_recv(c, &buf, 0); if (rc < 0) continue; - printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n", + pr_info("%s: i2c scan: found device @ 0x%x [%s]\n", name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } } @@ -381,7 +382,7 @@ int au0828_i2c_register(struct au0828_dev *dev) dev->i2c_adap.dev.parent = &dev->usbdev->dev; - strlcpy(dev->i2c_adap.name, DRIVER_NAME, + strlcpy(dev->i2c_adap.name, KBUILD_MODNAME, sizeof(dev->i2c_adap.name)); dev->i2c_adap.algo = &dev->i2c_algo; @@ -396,11 +397,11 @@ int au0828_i2c_register(struct au0828_dev *dev) dev->i2c_client.adapter = &dev->i2c_adap; if (0 == dev->i2c_rc) { - printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME); + pr_info("i2c bus registered\n"); if (i2c_scan) - do_i2c_scan(DRIVER_NAME, &dev->i2c_client); + do_i2c_scan(KBUILD_MODNAME, &dev->i2c_client); } else - printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME); + pr_info("i2c bus register FAILED\n"); return dev->i2c_rc; } diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 5efb83977f39..6db1ce8e09e1 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -17,6 +17,8 @@ GNU General Public License for more details. */ +#include "au0828.h" + #include #include #include @@ -29,8 +31,6 @@ static int disable_ir; module_param(disable_ir, int, 0444); MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); -#include "au0828.h" - struct au0828_rc { struct au0828_dev *dev; struct rc_dev *rc; diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c index 63f593070ee8..932d24f42b24 100644 --- a/drivers/media/usb/au0828/au0828-vbi.c +++ b/drivers/media/usb/au0828/au0828-vbi.c @@ -21,13 +21,13 @@ 02110-1301, USA. */ +#include "au0828.h" + #include #include #include #include -#include "au0828.h" - static unsigned int vbibufs = 5; module_param(vbibufs, int, 0644); MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 574a08c7013d..193b2e364266 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -28,6 +28,8 @@ * */ +#include "au0828.h" + #include #include #include @@ -36,7 +38,6 @@ #include #include #include -#include "au0828.h" #include "au0828-reg.h" static DEFINE_MUTEX(au0828_sysfs_lock); @@ -52,7 +53,7 @@ MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); #define au0828_isocdbg(fmt, arg...) \ do {\ if (isoc_debug) { \ - printk(KERN_INFO "au0828 %s :"fmt, \ + pr_info("au0828 %s :"fmt, \ __func__ , ##arg); \ } \ } while (0) @@ -105,12 +106,12 @@ static inline void print_err_status(struct au0828_dev *dev, static int check_dev(struct au0828_dev *dev) { if (dev->dev_state & DEV_DISCONNECTED) { - printk(KERN_INFO "v4l2 ioctl: device not present\n"); + pr_info("v4l2 ioctl: device not present\n"); return -ENODEV; } if (dev->dev_state & DEV_MISCONFIGURED) { - printk(KERN_INFO "v4l2 ioctl: device is misconfigured; " + pr_info("v4l2 ioctl: device is misconfigured; " "close and open it again\n"); return -EIO; } @@ -719,7 +720,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { rc = videobuf_iolock(vq, &buf->vb, NULL); if (rc < 0) { - printk(KERN_INFO "videobuf_iolock failed\n"); + pr_info("videobuf_iolock failed\n"); goto fail; } } @@ -732,7 +733,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, AU0828_MAX_ISO_BUFS, dev->max_pkt_size, au0828_isoc_copy); if (rc < 0) { - printk(KERN_INFO "au0828_init_isoc failed\n"); + pr_info("au0828_init_isoc failed\n"); goto fail; } } @@ -803,7 +804,7 @@ static int au0828_analog_stream_enable(struct au0828_dev *d) /* set au0828 interface0 to AS5 here again */ ret = usb_set_interface(d->usbdev, 0, 5); if (ret < 0) { - printk(KERN_INFO "Au0828 can't set alt setting to 5!\n"); + pr_info("Au0828 can't set alt setting to 5!\n"); return -EBUSY; } } @@ -1092,7 +1093,7 @@ static int au0828_v4l2_close(struct file *filp) USB bandwidth */ ret = usb_set_interface(dev->usbdev, 0, 0); if (ret < 0) - printk(KERN_INFO "Au0828 can't set alternate to 0!\n"); + pr_info("Au0828 can't set alternate to 0!\n"); } mutex_unlock(&dev->lock); @@ -1346,7 +1347,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, return rc; if (videobuf_queue_is_busy(&fh->vb_vidq)) { - printk(KERN_INFO "%s queue busy\n", __func__); + pr_info("%s queue busy\n", __func__); rc = -EBUSY; goto out; } @@ -1999,7 +2000,7 @@ int au0828_analog_register(struct au0828_dev *dev, retval = usb_set_interface(dev->usbdev, interface->cur_altsetting->desc.bInterfaceNumber, 5); if (retval != 0) { - printk(KERN_INFO "Failure setting usb interface0 to as5\n"); + pr_info("Failure setting usb interface0 to as5\n"); return retval; } @@ -2023,7 +2024,7 @@ int au0828_analog_register(struct au0828_dev *dev, } } if (!(dev->isoc_in_endpointaddr)) { - printk(KERN_INFO "Could not locate isoc endpoint\n"); + pr_info("Could not locate isoc endpoint\n"); kfree(dev); return -ENODEV; } diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 0d8cfe5cd264..d187129b96b7 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -42,7 +44,6 @@ #include "au0828-reg.h" #include "au0828-cards.h" -#define DRIVER_NAME "au0828" #define URB_COUNT 16 #define URB_BUFSIZE (0xe522) @@ -331,7 +332,7 @@ extern struct videobuf_queue_ops au0828_vbi_qops; #define dprintk(level, fmt, arg...)\ do { if (au0828_debug & level)\ - printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\ + printk(KERN_DEBUG pr_fmt(fmt), ## arg);\ } while (0) /* au0828-input.c */ -- GitLab From 811872404bb021b73ecb4b78de88bd2d7f26548e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:18 -0300 Subject: [PATCH 0487/5088] [media] au0828: add pr_info to track au0828 suspend/resume code Suspend/resume conditions can be very tricky. Add some info printk's to help tracking what's happening there. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 4 ++++ drivers/media/usb/au0828/au0828-dvb.c | 4 ++++ drivers/media/usb/au0828/au0828-input.c | 4 ++++ drivers/media/usb/au0828/au0828-video.c | 5 +++++ 4 files changed, 17 insertions(+) diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 452d14249348..bc064803b6c7 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -288,6 +288,8 @@ static int au0828_suspend(struct usb_interface *interface, if (!dev) return 0; + pr_info("Suspend\n"); + au0828_rc_suspend(dev); au0828_v4l2_suspend(dev); au0828_dvb_suspend(dev); @@ -303,6 +305,8 @@ static int au0828_resume(struct usb_interface *interface) if (!dev) return 0; + pr_info("Resume\n"); + /* Power Up the bridge */ au0828_write(dev, REG_600, 1 << 4); diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 99cf83bca033..ee45990c0be1 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -619,6 +619,8 @@ void au0828_dvb_suspend(struct au0828_dev *dev) struct au0828_dvb *dvb = &dev->dvb; if (dvb && dev->urb_streaming) { + pr_info("stopping DVB\n"); + cancel_work_sync(&dev->restart_streaming); /* Stop transport */ @@ -634,6 +636,8 @@ void au0828_dvb_resume(struct au0828_dev *dev) struct au0828_dvb *dvb = &dev->dvb; if (dvb && dev->urb_streaming) { + pr_info("resuming DVB\n"); + au0828_set_frontend(dvb->frontend); /* Start transport */ diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 6db1ce8e09e1..63995f97dc65 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -378,6 +378,8 @@ int au0828_rc_suspend(struct au0828_dev *dev) if (!ir) return 0; + pr_info("Stopping RC\n"); + cancel_delayed_work_sync(&ir->work); /* Disable IR */ @@ -393,6 +395,8 @@ int au0828_rc_resume(struct au0828_dev *dev) if (!ir) return 0; + pr_info("Restarting RC\n"); + /* Enable IR */ au8522_rc_set(ir, 0xe0, 1 << 4); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 193b2e364266..5f337b118bff 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1876,7 +1876,10 @@ void au0828_v4l2_suspend(struct au0828_dev *dev) struct urb *urb; int i; + pr_info("stopping V4L2\n"); + if (dev->stream_state == STREAM_ON) { + pr_info("stopping V4L2 active URBs\n"); au0828_analog_stream_disable(dev); /* stop urbs */ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { @@ -1900,6 +1903,8 @@ void au0828_v4l2_resume(struct au0828_dev *dev) { int i, rc; + pr_info("restarting V4L2\n"); + if (dev->stream_state == STREAM_ON) { au0828_stream_interrupt(dev); au0828_init_tuner(dev); -- GitLab From 59d7889ae49f6e3e9d9cff8c0de7ad95d9ca068b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:19 -0300 Subject: [PATCH 0488/5088] [media] dvb-frontend: add core support for tuner suspend/resume While several tuners have some sort of suspend/resume implementation, this is currently mangled with an optional .sleep callback that it is also used to put the device on low power mode. Not all drivers implement it, as returning the driver from low power may require to re-load the firmware, with takes some time. Also, some drivers may delay it. So, the more coherent is to add two new optional callbacks that will let the tuners to directy implement suspend and resume callbacks if they need. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 8 ++++++-- drivers/media/dvb-core/dvb_frontend.h | 2 ++ drivers/media/v4l2-core/tuner-core.c | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index c2a6a0a85813..a5810391af61 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2550,7 +2550,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe) dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, fe->id); - if (fe->ops.tuner_ops.sleep) + if (fe->ops.tuner_ops.suspend) + ret = fe->ops.tuner_ops.suspend(fe); + else if (fe->ops.tuner_ops.sleep) ret = fe->ops.tuner_ops.sleep(fe); if (fe->ops.sleep) @@ -2572,7 +2574,9 @@ int dvb_frontend_resume(struct dvb_frontend *fe) if (fe->ops.init) ret = fe->ops.init(fe); - if (fe->ops.tuner_ops.init) + if (fe->ops.tuner_ops.resume) + ret = fe->ops.tuner_ops.resume(fe); + else if (fe->ops.tuner_ops.init) ret = fe->ops.tuner_ops.init(fe); fe->exit = DVB_FE_NO_EXIT; diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index d398de4b6ef4..816269e5f706 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -201,6 +201,8 @@ struct dvb_tuner_ops { int (*release)(struct dvb_frontend *fe); int (*init)(struct dvb_frontend *fe); int (*sleep)(struct dvb_frontend *fe); + int (*suspend)(struct dvb_frontend *fe); + int (*resume)(struct dvb_frontend *fe); /** This is for simple PLLs - set all parameters in one go. */ int (*set_params)(struct dvb_frontend *fe); diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 06c18ba16fa0..177023200737 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -1260,7 +1260,9 @@ static int tuner_suspend(struct device *dev) tuner_dbg("suspend\n"); - if (!t->standby && analog_ops->standby) + if (t->fe.ops.tuner_ops.suspend) + t->fe.ops.tuner_ops.suspend(&t->fe); + else if (!t->standby && analog_ops->standby) analog_ops->standby(&t->fe); return 0; @@ -1273,7 +1275,9 @@ static int tuner_resume(struct device *dev) tuner_dbg("resume\n"); - if (!t->standby) + if (t->fe.ops.tuner_ops.resume) + t->fe.ops.tuner_ops.resume(&t->fe); + else if (!t->standby) if (set_mode(t, t->mode) == 0) set_freq(t, 0); -- GitLab From 91a5307cb0b164024725d68990441553740a2149 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:20 -0300 Subject: [PATCH 0489/5088] [media] xc5000: fix xc5000 suspend After xc5000 stops working, it waits for 5 seconds, waiting for a new usage. Only after that it goes to low power mode. If a suspend event happens before that, a work queue will remain active, with causes suspend to crash. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index e135760f7d48..af137046bfe5 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -1229,6 +1229,24 @@ static int xc5000_sleep(struct dvb_frontend *fe) return 0; } +static int xc5000_suspend(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __func__); + + cancel_delayed_work(&priv->timer_sleep); + + ret = xc5000_tuner_reset(fe); + if (ret != 0) + printk(KERN_ERR + "xc5000: %s() unable to shutdown tuner\n", + __func__); + + return 0; +} + static int xc5000_init(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; @@ -1293,6 +1311,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .release = xc5000_release, .init = xc5000_init, .sleep = xc5000_sleep, + .suspend = xc5000_suspend, .set_config = xc5000_set_config, .set_params = xc5000_set_params, -- GitLab From 164352023104207322614deef8d03bd0d773a22a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:21 -0300 Subject: [PATCH 0490/5088] [media] au0828: move the code that sets DTV on a separate function As we'll be adding a code to resume tuner operation, we need to move the code that actually sets DTV on a separate function, to be called by the resume code. No functional changes, just code got moved. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 79 ++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index af137046bfe5..3293fd8df59b 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -59,6 +59,7 @@ struct xc5000_priv { u32 freq_hz, freq_offset; u32 bandwidth; u8 video_standard; + unsigned int mode; u8 rf_mode; u8 radio_input; @@ -712,9 +713,50 @@ static void xc_debug_dump(struct xc5000_priv *priv) } } +static int xc5000_tune_digital(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + u32 bw = fe->dtv_property_cache.bandwidth_hz; + + ret = xc_set_signal_source(priv, priv->rf_mode); + if (ret != 0) { + printk(KERN_ERR + "xc5000: xc_set_signal_source(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_set_tv_standard(priv, + xc5000_standard[priv->video_standard].video_mode, + xc5000_standard[priv->video_standard].audio_mode, 0); + if (ret != 0) { + printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); + return -EREMOTEIO; + } + + ret = xc_set_IF_frequency(priv, priv->if_khz); + if (ret != 0) { + printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", + priv->if_khz); + return -EIO; + } + + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); + + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); + + if (debug) + xc_debug_dump(priv); + + priv->bandwidth = bw; + + return 0; +} + static int xc5000_set_params(struct dvb_frontend *fe) { - int ret, b; + int b; struct xc5000_priv *priv = fe->tuner_priv; u32 bw = fe->dtv_property_cache.bandwidth_hz; u32 freq = fe->dtv_property_cache.frequency; @@ -794,43 +836,12 @@ static int xc5000_set_params(struct dvb_frontend *fe) } priv->freq_hz = freq - priv->freq_offset; + priv->mode = V4L2_TUNER_DIGITAL_TV; dprintk(1, "%s() frequency=%d (compensated to %d)\n", __func__, freq, priv->freq_hz); - ret = xc_set_signal_source(priv, priv->rf_mode); - if (ret != 0) { - printk(KERN_ERR - "xc5000: xc_set_signal_source(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - ret = xc_set_tv_standard(priv, - xc5000_standard[priv->video_standard].video_mode, - xc5000_standard[priv->video_standard].audio_mode, 0); - if (ret != 0) { - printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n"); - return -EREMOTEIO; - } - - ret = xc_set_IF_frequency(priv, priv->if_khz); - if (ret != 0) { - printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", - priv->if_khz); - return -EIO; - } - - xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); - - xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); - - if (debug) - xc_debug_dump(priv); - - priv->bandwidth = bw; - - return 0; + return xc5000_tune_digital(fe); } static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) -- GitLab From c3d6676bbaf4666ded026b35e0f62156e59ecfc1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:22 -0300 Subject: [PATCH 0491/5088] [media] xc5000: Split config and set code for analog/radio As we need a function that reapply the last tuned radio, in order to do resume, split the code that validates and updates the internal priv struct from the ones that actually set radio and TV. A latter patch will add support for resume. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 81 ++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 3293fd8df59b..78695ed4549c 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -863,12 +863,10 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) return ret; } -static int xc5000_set_tv_freq(struct dvb_frontend *fe, - struct analog_parameters *params) +static void xc5000_config_tv(struct dvb_frontend *fe, + struct analog_parameters *params) { struct xc5000_priv *priv = fe->tuner_priv; - u16 pll_lock_status; - int ret; dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", __func__, params->frequency); @@ -887,42 +885,49 @@ static int xc5000_set_tv_freq(struct dvb_frontend *fe, if (params->std & V4L2_STD_MN) { /* default to BTSC audio standard */ priv->video_standard = MN_NTSC_PAL_BTSC; - goto tune_channel; + return; } if (params->std & V4L2_STD_PAL_BG) { /* default to NICAM audio standard */ priv->video_standard = BG_PAL_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_PAL_I) { /* default to NICAM audio standard */ priv->video_standard = I_PAL_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_PAL_DK) { /* default to NICAM audio standard */ priv->video_standard = DK_PAL_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_SECAM_DK) { /* default to A2 DK1 audio standard */ priv->video_standard = DK_SECAM_A2DK1; - goto tune_channel; + return; } if (params->std & V4L2_STD_SECAM_L) { priv->video_standard = L_SECAM_NICAM; - goto tune_channel; + return; } if (params->std & V4L2_STD_SECAM_LC) { priv->video_standard = LC_SECAM_NICAM; - goto tune_channel; + return; } +} + +static int xc5000_set_tv_freq(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + u16 pll_lock_status; + int ret; tune_channel: ret = xc_set_signal_source(priv, priv->rf_mode); @@ -966,12 +971,11 @@ static int xc5000_set_tv_freq(struct dvb_frontend *fe, return 0; } -static int xc5000_set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) +static int xc5000_config_radio(struct dvb_frontend *fe, + struct analog_parameters *params) + { struct xc5000_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - u8 radio_input; dprintk(1, "%s() frequency=%d (in units of khz)\n", __func__, params->frequency); @@ -981,6 +985,18 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, return -EINVAL; } + priv->freq_hz = params->frequency * 125 / 2; + priv->rf_mode = XC_RF_MODE_AIR; + + return 0; +} + +static int xc5000_set_radio_freq(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + u8 radio_input; + if (priv->radio_input == XC5000_RADIO_FM1) radio_input = FM_RADIO_INPUT1; else if (priv->radio_input == XC5000_RADIO_FM2) @@ -993,10 +1009,6 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, return -EINVAL; } - priv->freq_hz = params->frequency * 125 / 2; - - priv->rf_mode = XC_RF_MODE_AIR; - ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode, xc5000_standard[radio_input].audio_mode, radio_input); @@ -1024,11 +1036,27 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, return 0; } +static int xc5000_apply_params(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + switch (priv->mode) { + case V4L2_TUNER_RADIO: + return xc5000_set_radio_freq(fe); + case V4L2_TUNER_ANALOG_TV: + return xc5000_set_tv_freq(fe); + case V4L2_TUNER_DIGITAL_TV: + return xc5000_tune_digital(fe); + } + + return 0; +} + static int xc5000_set_analog_params(struct dvb_frontend *fe, struct analog_parameters *params) { struct xc5000_priv *priv = fe->tuner_priv; - int ret = -EINVAL; + int ret; if (priv->i2c_props.adap == NULL) return -EINVAL; @@ -1040,18 +1068,21 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe, switch (params->mode) { case V4L2_TUNER_RADIO: - ret = xc5000_set_radio_freq(fe, params); + ret = xc5000_config_radio(fe, params); + if (ret) + return ret; break; case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - ret = xc5000_set_tv_freq(fe, params); + xc5000_config_tv(fe, params); + break; + default: break; } + priv->mode = params->mode; - return ret; + return xc5000_apply_params(fe); } - static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) { struct xc5000_priv *priv = fe->tuner_priv; -- GitLab From 7ab1c07614b984778a808dc22f84b682fedefea1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:23 -0300 Subject: [PATCH 0492/5088] [media] xc5000: add a resume function If a device suspends/hibertates with a station tuned, restore the tuner station at resume. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 78695ed4549c..140c537bcfcc 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -1354,6 +1354,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .init = xc5000_init, .sleep = xc5000_sleep, .suspend = xc5000_suspend, + .resume = xc5000_apply_params, .set_config = xc5000_set_config, .set_params = xc5000_set_params, -- GitLab From 59b94f3e74042a82fd59478d688909760b873b02 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 21:47:24 -0300 Subject: [PATCH 0493/5088] [media] xc5000: better name the functions xc5000_set_params() is a bad name for a function that handles only digital TV. Rename it to xc5000_set_digital_params(), and proper name the generic function that works for both digital and analog. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 140c537bcfcc..c1905784b08e 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -754,7 +754,7 @@ static int xc5000_tune_digital(struct dvb_frontend *fe) return 0; } -static int xc5000_set_params(struct dvb_frontend *fe) +static int xc5000_set_digital_params(struct dvb_frontend *fe) { int b; struct xc5000_priv *priv = fe->tuner_priv; @@ -1036,7 +1036,7 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe) return 0; } -static int xc5000_apply_params(struct dvb_frontend *fe) +static int xc5000_set_params(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; @@ -1080,7 +1080,7 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe, } priv->mode = params->mode; - return xc5000_apply_params(fe); + return xc5000_set_params(fe); } static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) @@ -1354,10 +1354,10 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .init = xc5000_init, .sleep = xc5000_sleep, .suspend = xc5000_suspend, - .resume = xc5000_apply_params, + .resume = xc5000_set_params, .set_config = xc5000_set_config, - .set_params = xc5000_set_params, + .set_params = xc5000_set_digital_params, .set_analog_params = xc5000_set_analog_params, .get_frequency = xc5000_get_frequency, .get_if_frequency = xc5000_get_if_frequency, -- GitLab From bbc62a18b6d90da702d14f0d04f67de1e37ca790 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 23:14:20 -0300 Subject: [PATCH 0494/5088] [media] au0828: fix checks if dvb is initialized dev->dvb is always not null, as it is an area at the dev memory. So, checking if (dev->dvb) is always true. Instead of this stupid check, what the code wants to do is to know if the DVB was successully registered. Fix it by checking, instead, for dvb->frontend. It should also be sure that this var will be NULL if the device was not properly initialized. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-dvb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index ee45990c0be1..bc4ea5397e92 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -267,7 +267,7 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) if (!demux->dmx.frontend) return -EINVAL; - if (dvb) { + if (dvb->frontend) { mutex_lock(&dvb->lock); dvb->start_count++; dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__, @@ -296,7 +296,7 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) dprintk(1, "%s()\n", __func__); - if (dvb) { + if (dvb->frontend) { cancel_work_sync(&dev->restart_streaming); mutex_lock(&dvb->lock); @@ -526,8 +526,7 @@ void au0828_dvb_unregister(struct au0828_dev *dev) for (i = 0; i < URB_COUNT; i++) kfree(dev->dig_transfer_buffer[i]); } - - + dvb->frontend = NULL; } /* All the DVB attach calls go here, this function get's modified @@ -608,6 +607,7 @@ int au0828_dvb_register(struct au0828_dev *dev) if (ret < 0) { if (dvb->frontend->ops.release) dvb->frontend->ops.release(dvb->frontend); + dvb->frontend = NULL; return ret; } @@ -618,7 +618,7 @@ void au0828_dvb_suspend(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; - if (dvb && dev->urb_streaming) { + if (dvb->frontend && dev->urb_streaming) { pr_info("stopping DVB\n"); cancel_work_sync(&dev->restart_streaming); @@ -635,7 +635,7 @@ void au0828_dvb_resume(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; - if (dvb && dev->urb_streaming) { + if (dvb->frontend && dev->urb_streaming) { pr_info("resuming DVB\n"); au0828_set_frontend(dvb->frontend); -- GitLab From 2930977ac5934540d876715fdf32b1dd6f405df5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 23:14:21 -0300 Subject: [PATCH 0495/5088] [media] au0828: Fix DVB resume when streaming When DVB is streaming and suspend is called, it will call au0828_stop_transport(), with will clean the streaming flag. Due to that, stop_urb_transfer() will be called twice, causing an oops. So, we need another flag to be used at resume, telling it to restart DVB. While here, add a logic at stop_urb_transfer() to prevent it of being called twice, and convert the usb_streaming flag into boolean. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-dvb.c | 14 +++++++++----- drivers/media/usb/au0828/au0828.h | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index bc4ea5397e92..821f86e92cde 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -121,7 +121,7 @@ static void urb_completion(struct urb *purb) return; } - if (dev->urb_streaming == 0) { + if (!dev->urb_streaming) { dprintk(2, "%s: not streaming!\n", __func__); return; } @@ -159,7 +159,10 @@ static int stop_urb_transfer(struct au0828_dev *dev) dprintk(2, "%s()\n", __func__); - dev->urb_streaming = 0; + if (!dev->urb_streaming) + return 0; + + dev->urb_streaming = false; for (i = 0; i < URB_COUNT; i++) { if (dev->urbs[i]) { usb_kill_urb(dev->urbs[i]); @@ -229,7 +232,7 @@ static int start_urb_transfer(struct au0828_dev *dev) } } - dev->urb_streaming = 1; + dev->urb_streaming = true; ret = 0; err: @@ -323,7 +326,7 @@ static void au0828_restart_dvb_streaming(struct work_struct *work) restart_streaming); struct au0828_dvb *dvb = &dev->dvb; - if (dev->urb_streaming == 0) + if (!dev->urb_streaming) return; dprintk(1, "Restarting streaming...!\n"); @@ -628,6 +631,7 @@ void au0828_dvb_suspend(struct au0828_dev *dev) stop_urb_transfer(dev); au0828_stop_transport(dev, 1); mutex_unlock(&dvb->lock); + dev->need_urb_start = 1; } } @@ -635,7 +639,7 @@ void au0828_dvb_resume(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; - if (dvb->frontend && dev->urb_streaming) { + if (dvb->frontend && dev->need_urb_start) { pr_info("resuming DVB\n"); au0828_set_frontend(dvb->frontend); diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index d187129b96b7..a7cc6e397fdd 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -267,8 +267,8 @@ struct au0828_dev { char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc transfer */ - /* USB / URB Related */ - int urb_streaming; + /* DVB USB / URB Related */ + bool urb_streaming, need_urb_start; struct urb *urbs[URB_COUNT]; /* Preallocated transfer digital transfer buffers */ -- GitLab From 5275a3b6b01664317b1a0bdc95ad981dbbb62283 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Aug 2014 23:14:22 -0300 Subject: [PATCH 0496/5088] [media] xc5000: be sure that the firmware is there before set params Now that xc5000_set_params() is also called during resume, move the code that checks for the firmware to happen there. This way, the firmware will be loaded either for analog or digital TV when .resume callback is called. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index c1905784b08e..512fe508bcd2 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -1040,6 +1040,11 @@ static int xc5000_set_params(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; + if (xc_load_fw_and_init_tuner(fe, 0) != 0) { + dprintk(1, "Unable to load firmware and init tuner\n"); + return -EINVAL; + } + switch (priv->mode) { case V4L2_TUNER_RADIO: return xc5000_set_radio_freq(fe); @@ -1061,11 +1066,6 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe, if (priv->i2c_props.adap == NULL) return -EINVAL; - if (xc_load_fw_and_init_tuner(fe, 0) != 0) { - dprintk(1, "Unable to load firmware and init tuner\n"); - return -EINVAL; - } - switch (params->mode) { case V4L2_TUNER_RADIO: ret = xc5000_config_radio(fe, params); -- GitLab From 0fc87864879c46afe145e20ec09c9dba2328e3be Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 28 May 2014 09:38:21 -0300 Subject: [PATCH 0497/5088] [media] v4l: Add test pattern colour component controls In many cases the test pattern has selectable values for each colour component. Implement controls for raw bayer components. Additional controls should be defined for colour components that are not covered by these controls. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 34 ++++++++++++++++++++ drivers/media/v4l2-core/v4l2-ctrls.c | 4 +++ include/uapi/linux/v4l2-controls.h | 4 +++ 3 files changed, 42 insertions(+) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 9f5ffd85560b..a7eb1bde8b92 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -4790,6 +4790,40 @@ interface and may change in the future. conversion. + + V4L2_CID_TEST_PATTERN_RED + integer + + + Test pattern red colour component. + + + + V4L2_CID_TEST_PATTERN_GREENR + integer + + + Test pattern green (next to red) + colour component. + + + + V4L2_CID_TEST_PATTERN_BLUE + integer + + + Test pattern blue colour component. + + + + V4L2_CID_TEST_PATTERN_GREENB + integer + + + Test pattern green (next to blue) + colour component. + + diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index f030d6a9e044..35d1f3d5045b 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -859,6 +859,10 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_VBLANK: return "Vertical Blanking"; case V4L2_CID_HBLANK: return "Horizontal Blanking"; case V4L2_CID_ANALOGUE_GAIN: return "Analogue Gain"; + case V4L2_CID_TEST_PATTERN_RED: return "Red Pixel Value"; + case V4L2_CID_TEST_PATTERN_GREENR: return "Green (Red) Pixel Value"; + case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value"; + case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value"; /* Image processing controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index e946e43fb8d5..8b930210a4b9 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -865,6 +865,10 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_VBLANK (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1) #define V4L2_CID_HBLANK (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2) #define V4L2_CID_ANALOGUE_GAIN (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3) +#define V4L2_CID_TEST_PATTERN_RED (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 4) +#define V4L2_CID_TEST_PATTERN_GREENR (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 5) +#define V4L2_CID_TEST_PATTERN_BLUE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6) +#define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7) /* Image processing controls */ -- GitLab From a913d8742e275dd2d80726afac02311a0f49d161 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 26 May 2014 09:46:18 -0300 Subject: [PATCH 0498/5088] [media] smiapp: Add driver-specific test pattern menu item definitions Add numeric definitions for menu items used in the smiapp driver's test pattern menu. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Acked-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/Kbuild | 1 + include/uapi/linux/smiapp.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 include/uapi/linux/smiapp.h diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 24e9033f8b3f..4ec377d103c7 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -353,6 +353,7 @@ header-y += serio.h header-y += shm.h header-y += signal.h header-y += signalfd.h +header-y += smiapp.h header-y += snmp.h header-y += sock_diag.h header-y += socket.h diff --git a/include/uapi/linux/smiapp.h b/include/uapi/linux/smiapp.h new file mode 100644 index 000000000000..53938f4412ee --- /dev/null +++ b/include/uapi/linux/smiapp.h @@ -0,0 +1,29 @@ +/* + * include/uapi/linux/smiapp.h + * + * Generic driver for SMIA/SMIA++ compliant camera modules + * + * Copyright (C) 2014 Intel Corporation + * Contact: Sakari Ailus + * + * 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 __UAPI_LINUX_SMIAPP_H_ +#define __UAPI_LINUX_SMIAPP_H_ + +#define V4L2_SMIAPP_TEST_PATTERN_MODE_DISABLED 0 +#define V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR 1 +#define V4L2_SMIAPP_TEST_PATTERN_MODE_COLOUR_BARS 2 +#define V4L2_SMIAPP_TEST_PATTERN_MODE_COLOUR_BARS_GREY 3 +#define V4L2_SMIAPP_TEST_PATTERN_MODE_PN9 4 + +#endif /* __UAPI_LINUX_SMIAPP_H_ */ -- GitLab From 0e2a6b7f2b9303410c93fd4724f9d36ebc7be1c3 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 21 May 2014 16:58:11 -0300 Subject: [PATCH 0499/5088] [media] smiapp: Implement the test pattern control Add support for the V4L2_CID_TEST_PATTERN control. When the solid colour mode is selected, additional controls become available for setting the solid four solid colour components. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 79 ++++++++++++++++++++++++-- drivers/media/i2c/smiapp/smiapp.h | 4 ++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 1eaf975d3612..437ec29bdf64 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -31,8 +31,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -404,6 +405,14 @@ static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor) pixel_order_str[pixel_order]); } +static const char * const smiapp_test_patterns[] = { + "Disabled", + "Solid Colour", + "Eight Vertical Colour Bars", + "Colour Bars With Fade to Grey", + "Pseudorandom Sequence (PN9)", +}; + static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) { struct smiapp_sensor *sensor = @@ -477,6 +486,35 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) return smiapp_pll_update(sensor); + case V4L2_CID_TEST_PATTERN: { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) + v4l2_ctrl_activate( + sensor->test_data[i], + ctrl->val == + V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR); + + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_PATTERN_MODE, ctrl->val); + } + + case V4L2_CID_TEST_PATTERN_RED: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_RED, ctrl->val); + + case V4L2_CID_TEST_PATTERN_GREENR: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_GREENR, ctrl->val); + + case V4L2_CID_TEST_PATTERN_BLUE: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_BLUE, ctrl->val); + + case V4L2_CID_TEST_PATTERN_GREENB: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_GREENB, ctrl->val); + default: return -EINVAL; } @@ -489,10 +527,10 @@ static const struct v4l2_ctrl_ops smiapp_ctrl_ops = { static int smiapp_init_controls(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int max; + unsigned int max, i; int rval; - rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7); + rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12); if (rval) return rval; sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; @@ -535,6 +573,20 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); + v4l2_ctrl_new_std_menu_items(&sensor->pixel_array->ctrl_handler, + &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(smiapp_test_patterns) - 1, + 0, 0, smiapp_test_patterns); + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { + int max_value = (1 << sensor->csi_format->width) - 1; + sensor->test_data[i] = + v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, + &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, + 0, max_value, 1, max_value); + } + if (sensor->pixel_array->ctrl_handler.error) { dev_err(&client->dev, "pixel array controls initialization failed (%d)\n", @@ -1671,17 +1723,34 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, if (fmt->pad == ssd->source_pad) { u32 code = fmt->format.code; int rval = __smiapp_get_format(subdev, fh, fmt); + bool range_changed = false; + unsigned int i; if (!rval && subdev == &sensor->src->sd) { const struct smiapp_csi_data_format *csi_format = smiapp_validate_csi_data_format(sensor, code); - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (csi_format->width != + sensor->csi_format->width) + range_changed = true; + sensor->csi_format = csi_format; + } + fmt->format.code = csi_format->code; } mutex_unlock(&sensor->mutex); - return rval; + if (rval || !range_changed) + return rval; + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) + v4l2_ctrl_modify_range( + sensor->test_data[i], + 0, (1 << sensor->csi_format->width) - 1, 1, 0); + + return 0; } /* Sink pad. Width and height are changeable here. */ diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 7cc5aae662fd..874b49ffd88f 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -54,6 +54,8 @@ (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \ + (clk) / 1000 - 1) / ((clk) / 1000)) +#define SMIAPP_COLOUR_COMPONENTS 4 + #include "smiapp-limits.h" struct smiapp_quirk; @@ -241,6 +243,8 @@ struct smiapp_sensor { /* src controls */ struct v4l2_ctrl *link_freq; struct v4l2_ctrl *pixel_rate_csi; + /* test pattern colour components */ + struct v4l2_ctrl *test_data[SMIAPP_COLOUR_COMPONENTS]; }; #define to_smiapp_subdev(_sd) \ -- GitLab From 24acf8b211e25414cb288305292a1fda136c0bd8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 11:36:23 -0300 Subject: [PATCH 0500/5088] [media] v4l: subdev: Extend default link validation to cover field order The field order must match between the source and sink pads, or the sink pad field order must be NONE. This allows connecting an interlaced source to a bridge that has no hardware support for interlaced formats. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index b4d235c13fbf..543631c3557a 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -501,11 +501,20 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, struct v4l2_subdev_format *source_fmt, struct v4l2_subdev_format *sink_fmt) { + /* The width, height and code must match. */ if (source_fmt->format.width != sink_fmt->format.width || source_fmt->format.height != sink_fmt->format.height || source_fmt->format.code != sink_fmt->format.code) return -EINVAL; + /* The field order must match, or the sink field order must be NONE + * to support interlaced hardware connected to bridges that support + * progressive formats only. + */ + if (source_fmt->format.field != sink_fmt->format.field && + sink_fmt->format.field != V4L2_FIELD_NONE) + return -EINVAL; + return 0; } EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default); -- GitLab From eb228e897c902a65f6da536331f7d058fde1ea73 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 20 May 2014 18:21:13 -0300 Subject: [PATCH 0501/5088] [media] omap3isp: Don't ignore subdev streamoff failures Record the value returned by subdevs from s_stream(0) and handle stop failures when an error occurs. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 2c7aa6720569..7b10c461a497 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -999,16 +999,14 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) video, s_stream, 0); } - v4l2_subdev_call(subdev, video, s_stream, 0); + ret = v4l2_subdev_call(subdev, video, s_stream, 0); if (subdev == &isp->isp_res.subdev) - ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer); + ret |= isp_pipeline_wait(isp, isp_pipeline_wait_resizer); else if (subdev == &isp->isp_prev.subdev) - ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview); + ret |= isp_pipeline_wait(isp, isp_pipeline_wait_preview); else if (subdev == &isp->isp_ccdc.subdev) - ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc); - else - ret = 0; + ret |= isp_pipeline_wait(isp, isp_pipeline_wait_ccdc); /* Handle stop failures. An entity that fails to stop can * usually just be restarted. Flag the stop failure nonetheless -- GitLab From 9884a955a9da8488a88672a3eff40309bbd7f74f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 18:17:55 -0300 Subject: [PATCH 0502/5088] [media] omap3isp: Remove boilerplate disclaimer and FSF address We don't want to modify all source files the day the FSF moves. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/cfa_coef_table.h | 10 ---------- drivers/media/platform/omap3isp/gamma_table.h | 10 ---------- drivers/media/platform/omap3isp/isp.c | 10 ---------- drivers/media/platform/omap3isp/isp.h | 10 ---------- drivers/media/platform/omap3isp/ispccdc.c | 10 ---------- drivers/media/platform/omap3isp/ispccdc.h | 10 ---------- drivers/media/platform/omap3isp/ispccp2.c | 10 ---------- drivers/media/platform/omap3isp/ispccp2.h | 10 ---------- drivers/media/platform/omap3isp/ispcsi2.c | 10 ---------- drivers/media/platform/omap3isp/ispcsi2.h | 10 ---------- drivers/media/platform/omap3isp/ispcsiphy.c | 10 ---------- drivers/media/platform/omap3isp/ispcsiphy.h | 10 ---------- drivers/media/platform/omap3isp/isph3a.h | 10 ---------- drivers/media/platform/omap3isp/isph3a_aewb.c | 10 ---------- drivers/media/platform/omap3isp/isph3a_af.c | 10 ---------- drivers/media/platform/omap3isp/isphist.c | 10 ---------- drivers/media/platform/omap3isp/isphist.h | 10 ---------- drivers/media/platform/omap3isp/isppreview.c | 10 ---------- drivers/media/platform/omap3isp/isppreview.h | 10 ---------- drivers/media/platform/omap3isp/ispreg.h | 10 ---------- drivers/media/platform/omap3isp/ispresizer.c | 10 ---------- drivers/media/platform/omap3isp/ispresizer.h | 10 ---------- drivers/media/platform/omap3isp/ispstat.c | 10 ---------- drivers/media/platform/omap3isp/ispstat.h | 10 ---------- drivers/media/platform/omap3isp/ispvideo.c | 10 ---------- drivers/media/platform/omap3isp/ispvideo.h | 10 ---------- drivers/media/platform/omap3isp/luma_enhance_table.h | 10 ---------- drivers/media/platform/omap3isp/noise_filter_table.h | 10 ---------- 28 files changed, 280 deletions(-) diff --git a/drivers/media/platform/omap3isp/cfa_coef_table.h b/drivers/media/platform/omap3isp/cfa_coef_table.h index c84df0706f3e..e75b0eb2519b 100644 --- a/drivers/media/platform/omap3isp/cfa_coef_table.h +++ b/drivers/media/platform/omap3isp/cfa_coef_table.h @@ -11,16 +11,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. - * - * 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 */ { 244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, diff --git a/drivers/media/platform/omap3isp/gamma_table.h b/drivers/media/platform/omap3isp/gamma_table.h index 78deebf7d965..3b507078016d 100644 --- a/drivers/media/platform/omap3isp/gamma_table.h +++ b/drivers/media/platform/omap3isp/gamma_table.h @@ -12,16 +12,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. - * - * 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 */ 0, 0, 1, 2, 3, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 7b10c461a497..72265e58ca60 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -40,16 +40,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. - * - * 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 */ #include diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 2c314eea1252..cfdfc8714b6b 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -12,16 +12,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. - * - * 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 OMAP3_ISP_CORE_H diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 9f727d20f06d..64092923feac 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -12,16 +12,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. - * - * 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 */ #include diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index f65061602c71..dd999be7f82e 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -12,16 +12,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. - * - * 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 OMAP3_ISP_CCDC_H diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index f3801db9095c..9cb49b3c04bd 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -12,16 +12,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. - * - * 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 */ #include diff --git a/drivers/media/platform/omap3isp/ispccp2.h b/drivers/media/platform/omap3isp/ispccp2.h index 76d65f4576ef..4662bffa79e3 100644 --- a/drivers/media/platform/omap3isp/ispccp2.h +++ b/drivers/media/platform/omap3isp/ispccp2.h @@ -12,16 +12,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. - * - * 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 OMAP3_ISP_CCP2_H diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 5a2e47e58b84..6530b255f103 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -12,16 +12,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. - * - * 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 */ #include #include diff --git a/drivers/media/platform/omap3isp/ispcsi2.h b/drivers/media/platform/omap3isp/ispcsi2.h index c57729b7e86e..453ed62fe394 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.h +++ b/drivers/media/platform/omap3isp/ispcsi2.h @@ -12,16 +12,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. - * - * 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 OMAP3_ISP_CSI2_H diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c index c09de32f986a..e033f2237a72 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/omap3isp/ispcsiphy.c @@ -12,16 +12,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. - * - * 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 */ #include diff --git a/drivers/media/platform/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h index 14551fd77697..e17c88beab92 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.h +++ b/drivers/media/platform/omap3isp/ispcsiphy.h @@ -12,16 +12,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. - * - * 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 OMAP3_ISP_CSI_PHY_H diff --git a/drivers/media/platform/omap3isp/isph3a.h b/drivers/media/platform/omap3isp/isph3a.h index fb09fd4ca755..e5b28d0f3b0f 100644 --- a/drivers/media/platform/omap3isp/isph3a.h +++ b/drivers/media/platform/omap3isp/isph3a.h @@ -13,16 +13,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. - * - * 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 OMAP3_ISP_H3A_H diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c index d6811ce263eb..b208c5417146 100644 --- a/drivers/media/platform/omap3isp/isph3a_aewb.c +++ b/drivers/media/platform/omap3isp/isph3a_aewb.c @@ -13,16 +13,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. - * - * 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 */ #include diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c index 6fc960cd30f5..8a83e195f3e3 100644 --- a/drivers/media/platform/omap3isp/isph3a_af.c +++ b/drivers/media/platform/omap3isp/isph3a_af.c @@ -13,16 +13,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. - * - * 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 */ /* Linux specific include files */ diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index 06a5f8164eaa..ce822c34c843 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c @@ -13,16 +13,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. - * - * 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 */ #include diff --git a/drivers/media/platform/omap3isp/isphist.h b/drivers/media/platform/omap3isp/isphist.h index 0b2a38ec94c4..3b5415517dcd 100644 --- a/drivers/media/platform/omap3isp/isphist.h +++ b/drivers/media/platform/omap3isp/isphist.h @@ -13,16 +13,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. - * - * 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 OMAP3_ISP_HIST_H diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 720809b07e75..605f57ef0a49 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -12,16 +12,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. - * - * 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 */ #include diff --git a/drivers/media/platform/omap3isp/isppreview.h b/drivers/media/platform/omap3isp/isppreview.h index f66923407f8c..16fdc03a3d43 100644 --- a/drivers/media/platform/omap3isp/isppreview.h +++ b/drivers/media/platform/omap3isp/isppreview.h @@ -12,16 +12,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. - * - * 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 OMAP3_ISP_PREVIEW_H diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index b7d90e6fb01d..f37a8df23cf6 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -12,16 +12,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. - * - * 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 OMAP3_ISP_REG_H diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 6f077c2377db..93104b0957b3 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -12,16 +12,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. - * - * 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 */ #include diff --git a/drivers/media/platform/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h index 9b01e9047c15..494f5a2fd4bb 100644 --- a/drivers/media/platform/omap3isp/ispresizer.h +++ b/drivers/media/platform/omap3isp/ispresizer.h @@ -12,16 +12,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. - * - * 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 OMAP3_ISP_RESIZER_H diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index e6cbc1eaf4ca..a94e8340508f 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -13,16 +13,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. - * - * 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 */ #include diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h index 58d6ac7cb664..b32b29677e2c 100644 --- a/drivers/media/platform/omap3isp/ispstat.h +++ b/drivers/media/platform/omap3isp/ispstat.h @@ -13,16 +13,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. - * - * 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 OMAP3_ISP_STAT_H diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index e36bac26476c..04d45e70d3be 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -11,16 +11,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. - * - * 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 */ #include diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h index 7d2e82122ecd..a76124cd6431 100644 --- a/drivers/media/platform/omap3isp/ispvideo.h +++ b/drivers/media/platform/omap3isp/ispvideo.h @@ -11,16 +11,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. - * - * 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 OMAP3_ISP_VIDEO_H diff --git a/drivers/media/platform/omap3isp/luma_enhance_table.h b/drivers/media/platform/omap3isp/luma_enhance_table.h index 098b45e2280f..81c5b1566469 100644 --- a/drivers/media/platform/omap3isp/luma_enhance_table.h +++ b/drivers/media/platform/omap3isp/luma_enhance_table.h @@ -12,16 +12,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. - * - * 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 */ 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, diff --git a/drivers/media/platform/omap3isp/noise_filter_table.h b/drivers/media/platform/omap3isp/noise_filter_table.h index d50451a4a242..5073f9847937 100644 --- a/drivers/media/platform/omap3isp/noise_filter_table.h +++ b/drivers/media/platform/omap3isp/noise_filter_table.h @@ -12,16 +12,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. - * - * 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 */ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -- GitLab From 25c5cc9194f241d9180b4ca76a1845efd0a02769 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 10:33:15 -0300 Subject: [PATCH 0503/5088] [media] omap3isp: Move non-critical code out of the mutex-protected section The isp_video_pix_to_mbus() and isp_video_mbus_to_pix() calls in isp_video_set_format() only access static fields of the isp_video structure. They don't need to be protected by a mutex. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispvideo.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 04d45e70d3be..2876f34b84c0 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -631,17 +631,16 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) if (format->type != video->type) return -EINVAL; - mutex_lock(&video->mutex); - /* Fill the bytesperline and sizeimage fields by converting to media bus * format and back to pixel format. */ isp_video_pix_to_mbus(&format->fmt.pix, &fmt); isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix); + mutex_lock(&video->mutex); vfh->format = *format; - mutex_unlock(&video->mutex); + return 0; } -- GitLab From 48a8a0cb764c25939788a476e7f1b1695c337835 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 10:49:58 -0300 Subject: [PATCH 0504/5088] [media] omap3isp: Default to progressive field order when setting the format If the requested field order is not supported default to progressive as we can't guess how the user will configure the pipeline later on. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispvideo.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 2876f34b84c0..2fe1c463232d 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -631,6 +631,15 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) if (format->type != video->type) return -EINVAL; + /* Default to the progressive field order if the requested value is not + * supported (or set to ANY). The only supported orders are progressive + * (available on all video nodes) and alternate (available on capture + * nodes only). + */ + if (format->fmt.pix.field != V4L2_FIELD_ALTERNATE || + video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + format->fmt.pix.field = V4L2_FIELD_NONE; + /* Fill the bytesperline and sizeimage fields by converting to media bus * format and back to pixel format. */ -- GitLab From f7abbe989f7aa5e1d65fc7f171b8c144f4382045 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 12:14:42 -0300 Subject: [PATCH 0505/5088] [media] omap3isp: video: Validate the video node field order The field order requested on the video node must match the field order at the connected subdevice source pad. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispvideo.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 2fe1c463232d..756c1628ef86 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -309,10 +309,11 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh) vfh->format.fmt.pix.height != format.fmt.pix.height || vfh->format.fmt.pix.width != format.fmt.pix.width || vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline || - vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage) + vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage || + vfh->format.fmt.pix.field != format.fmt.pix.field) return -EINVAL; - return ret; + return 0; } /* ----------------------------------------------------------------------------- -- GitLab From 2e8f01725e332c8998b87a6fe09cfc3b105eb643 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 15:05:51 -0300 Subject: [PATCH 0506/5088] [media] omap3isp: ccdc: Simplify the configuration function Assign the format variable to the sink pad format earlier and use it instead of accessing the sink pad format directly from the ISP structure. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 64092923feac..8fbba95115ad 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1114,6 +1114,9 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) ->bus.parallel; + /* CCDC_PAD_SINK */ + format = &ccdc->formats[CCDC_PAD_SINK]; + /* Compute the lane shifter shift value and enable the bridge when the * input format is YUV. */ @@ -1124,8 +1127,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) depth_in = fmt_info->width; } - fmt_info = omap3isp_video_format_info - (isp->isp_ccdc.formats[CCDC_PAD_SINK].code); + fmt_info = omap3isp_video_format_info(format->code); depth_out = fmt_info->width; shift = depth_in - depth_out; @@ -1157,9 +1159,6 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) else syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ; - /* CCDC_PAD_SINK */ - format = &ccdc->formats[CCDC_PAD_SINK]; - /* Mosaic filter */ switch (format->code) { case V4L2_MBUS_FMT_SRGGB10_1X10: -- GitLab From 0a7b1a01037e0d43e1b85134be4217c7831f57d6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 21:46:33 -0300 Subject: [PATCH 0507/5088] [media] omap3isp: ccdc: Simplify the ccdc_isr_buffer() function Instead of using goto statements to a single line return, return the correct value immediately. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 8fbba95115ad..76d4fd73f5e8 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1480,7 +1480,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); struct isp_device *isp = to_isp_device(ccdc); struct isp_buffer *buffer; - int restart = 0; /* The CCDC generates VD0 interrupts even when disabled (the datasheet * doesn't explicitly state if that's supposed to happen or not, so it @@ -1489,30 +1488,27 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) * would thus not be enough, we need to handle the situation explicitly. */ if (list_empty(&ccdc->video_out.dmaqueue)) - goto done; + return 0; /* We're in continuous mode, and memory writes were disabled due to a * buffer underrun. Reenable them now that we have a buffer. The buffer * address has been set in ccdc_video_queue. */ if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) { - restart = 1; ccdc->underrun = 0; - goto done; + return 1; } if (ccdc_sbl_wait_idle(ccdc, 1000)) { dev_info(isp->dev, "CCDC won't become idle!\n"); isp->crashed |= 1U << ccdc->subdev.entity.id; omap3isp_pipeline_cancel_stream(pipe); - goto done; + return 0; } buffer = omap3isp_video_buffer_next(&ccdc->video_out); - if (buffer != NULL) { + if (buffer != NULL) ccdc_set_outaddr(ccdc, buffer->dma); - restart = 1; - } pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; @@ -1521,8 +1517,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_SINGLESHOT); -done: - return restart; + return buffer != NULL; } /* -- GitLab From 9a36d8ed33c481a99f69f8a2eeb22e3c7750e522 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 16:37:38 -0300 Subject: [PATCH 0508/5088] [media] omap3isp: ccdc: Add basic support for interlaced video When the CCDC input is interlaced enable the alternate field order on the CCDC output video node. The field signal polarity is specified through platform data. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 21 ++++++++++++++++++++- drivers/media/platform/omap3isp/ispvideo.c | 6 ++++++ drivers/media/platform/omap3isp/ispvideo.h | 2 ++ include/media/omap3isp.h | 3 +++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 76d4fd73f5e8..49d7256a7de3 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1001,6 +1001,9 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, if (pdata && pdata->vs_pol) syn_mode |= ISPCCDC_SYN_MODE_VDPOL; + if (pdata && pdata->fld_pol) + syn_mode |= ISPCCDC_SYN_MODE_FLDPOL; + isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); /* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The @@ -1140,6 +1143,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge); + /* Configure the sync interface. */ ccdc_config_sync_if(ccdc, pdata, depth_out); syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); @@ -1499,6 +1503,17 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 1; } + /* When capturing fields in alternate order read the current field + * identifier and store it in the pipeline. + */ + if (ccdc->formats[CCDC_PAD_SOURCE_OF].field == V4L2_FIELD_ALTERNATE) { + u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_SYN_MODE); + + pipe->field = syn_mode & ISPCCDC_SYN_MODE_FLDSTAT + ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; + } + if (ccdc_sbl_wait_idle(ccdc, 1000)) { dev_info(isp->dev, "CCDC won't become idle!\n"); isp->crashed |= 1U << ccdc->subdev.entity.id; @@ -1830,6 +1845,11 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, /* Clamp the input size. */ fmt->width = clamp_t(u32, width, 32, 4096); fmt->height = clamp_t(u32, height, 32, 4096); + + /* Default to progressive field order. */ + if (fmt->field == V4L2_FIELD_ANY) + fmt->field = V4L2_FIELD_NONE; + break; case CCDC_PAD_SOURCE_OF: @@ -1885,7 +1905,6 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, * stored on 2 bytes. */ fmt->colorspace = V4L2_COLORSPACE_SRGB; - fmt->field = V4L2_FIELD_NONE; } /* diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 756c1628ef86..c38f1d4cc538 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -482,6 +482,11 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) else buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number); + if (pipe->field != V4L2_FIELD_NONE) + buf->vb.v4l2_buf.sequence /= 2; + + buf->vb.v4l2_buf.field = pipe->field; + /* Report pipeline errors to userspace on the capture device side. */ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) { state = VB2_BUF_STATE_ERROR; @@ -1038,6 +1043,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) video->queue = &vfh->queue; INIT_LIST_HEAD(&video->dmaqueue); atomic_set(&pipe->frame_number, -1); + pipe->field = vfh->format.fmt.pix.field; mutex_lock(&video->queue_lock); ret = vb2_streamon(&vfh->queue, type); diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h index a76124cd6431..0b7efedc3da9 100644 --- a/drivers/media/platform/omap3isp/ispvideo.h +++ b/drivers/media/platform/omap3isp/ispvideo.h @@ -78,6 +78,7 @@ enum isp_pipeline_state { /* * struct isp_pipeline - An ISP hardware pipeline + * @field: The field being processed by the pipeline * @error: A hardware error occurred during capture * @entities: Bitmask of entities in the pipeline (indexed by entity ID) */ @@ -91,6 +92,7 @@ struct isp_pipeline { u32 entities; unsigned long l3_ick; unsigned int max_rate; + enum v4l2_field field; atomic_t frame_number; bool do_propagation; /* of frame number */ bool error; diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h index c9d06d9f7e6e..398279dd1922 100644 --- a/include/media/omap3isp.h +++ b/include/media/omap3isp.h @@ -57,6 +57,8 @@ enum { * 0 - Active high, 1 - Active low * @vs_pol: Vertical synchronization polarity * 0 - Active high, 1 - Active low + * @fld_pol: Field signal polarity + * 0 - Positive, 1 - Negative * @data_pol: Data polarity * 0 - Normal, 1 - One's complement */ @@ -65,6 +67,7 @@ struct isp_parallel_platform_data { unsigned int clk_pol:1; unsigned int hs_pol:1; unsigned int vs_pol:1; + unsigned int fld_pol:1; unsigned int data_pol:1; }; -- GitLab From bcb4e0efd1380d93866df51ec5d8dfaa026537ad Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 19 May 2014 19:40:04 -0300 Subject: [PATCH 0509/5088] [media] omap3isp: ccdc: Support the interlaced field orders at the CCDC output The CCDC can interleave fields into a single buffer when writing to memory. Support it. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 132 ++++++++++++++------- drivers/media/platform/omap3isp/ispreg.h | 10 +- drivers/media/platform/omap3isp/ispvideo.c | 40 +++++-- 3 files changed, 122 insertions(+), 60 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 49d7256a7de3..8d1861d948d0 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -863,52 +863,51 @@ static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable) /* * ccdc_config_outlineoffset - Configure memory saving output line offset * @ccdc: Pointer to ISP CCDC device. - * @offset: Address offset to start a new line. Must be twice the - * Output width and aligned on 32 byte boundary - * @oddeven: Specifies the odd/even line pattern to be chosen to store the - * output. - * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines. + * @bpl: Number of bytes per line when stored in memory. + * @field: Field order when storing interlaced formats in memory. * - * - Configures the output line offset when stored in memory - * - Sets the odd/even line pattern to store the output - * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4)) - * - Configures the number of even and odd line fields in case of rearranging - * the lines. + * Configure the offsets for the line output control: + * + * - The horizontal line offset is defined as the number of bytes between the + * start of two consecutive lines in memory. Set it to the given bytes per + * line value. + * + * - The field offset value is defined as the number of lines to offset the + * start of the field identified by FID = 1. Set it to one. + * + * - The line offset values are defined as the number of lines (as defined by + * the horizontal line offset) between the start of two consecutive lines for + * all combinations of odd/even lines in odd/even fields. When interleaving + * fields set them all to two lines, and to one line otherwise. */ static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc, - u32 offset, u8 oddeven, u8 numlines) + unsigned int bpl, + enum v4l2_field field) { struct isp_device *isp = to_isp_device(ccdc); + u32 sdofst = 0; - isp_reg_writel(isp, offset & 0xffff, - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF); - - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - ISPCCDC_SDOFST_FINV); + isp_reg_writel(isp, bpl & 0xffff, OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_HSIZE_OFF); - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - ISPCCDC_SDOFST_FOFST_4L); - - switch (oddeven) { - case EVENEVEN: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT); - break; - case ODDEVEN: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT); - break; - case EVENODD: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT); - break; - case ODDODD: - isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, - (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT); + switch (field) { + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + /* When interleaving fields in memory offset field one by one + * line and set the line offset to two lines. + */ + sdofst |= (1 << ISPCCDC_SDOFST_LOFST0_SHIFT) + | (1 << ISPCCDC_SDOFST_LOFST1_SHIFT) + | (1 << ISPCCDC_SDOFST_LOFST2_SHIFT) + | (1 << ISPCCDC_SDOFST_LOFST3_SHIFT); break; + default: + /* In all other cases set the line offsets to one line. */ break; } + + isp_reg_writel(isp, sdofst, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST); } /* @@ -1204,7 +1203,17 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) << ISPCCDC_VERT_LINES_NLV_SHIFT, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES); - ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0); + ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, + format->field); + + /* When interleaving fields enable processing of the field input signal. + * This will cause the line output control module to apply the field + * offset to field 1. + */ + if (ccdc->formats[CCDC_PAD_SINK].field == V4L2_FIELD_ALTERNATE && + (format->field == V4L2_FIELD_INTERLACED_TB || + format->field == V4L2_FIELD_INTERLACED_BT)) + syn_mode |= ISPCCDC_SYN_MODE_FLDMODE; /* The CCDC outputs data in UYVY order by default. Swap bytes to get * YUYV. @@ -1484,6 +1493,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); struct isp_device *isp = to_isp_device(ccdc); struct isp_buffer *buffer; + enum v4l2_field field; /* The CCDC generates VD0 interrupts even when disabled (the datasheet * doesn't explicitly state if that's supposed to happen or not, so it @@ -1503,17 +1513,12 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 1; } - /* When capturing fields in alternate order read the current field - * identifier and store it in the pipeline. - */ - if (ccdc->formats[CCDC_PAD_SOURCE_OF].field == V4L2_FIELD_ALTERNATE) { - u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, - ISPCCDC_SYN_MODE); - - pipe->field = syn_mode & ISPCCDC_SYN_MODE_FLDSTAT - ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; - } + /* Read the current field identifier. */ + field = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE) + & ISPCCDC_SYN_MODE_FLDSTAT + ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; + /* Wait for the CCDC to become idle. */ if (ccdc_sbl_wait_idle(ccdc, 1000)) { dev_info(isp->dev, "CCDC won't become idle!\n"); isp->crashed |= 1U << ccdc->subdev.entity.id; @@ -1521,6 +1526,28 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 0; } + switch (ccdc->formats[CCDC_PAD_SOURCE_OF].field) { + case V4L2_FIELD_ALTERNATE: + /* When capturing fields in alternate order store the current + * field identifier in the pipeline. + */ + pipe->field = field; + break; + + case V4L2_FIELD_INTERLACED_TB: + /* When interleaving fields only complete the buffer after + * capturing the second field. + */ + if (field == V4L2_FIELD_TOP) + return 1; + break; + + case V4L2_FIELD_INTERLACED_BT: + if (field == V4L2_FIELD_BOTTOM) + return 1; + break; + } + buffer = omap3isp_video_buffer_next(&ccdc->video_out); if (buffer != NULL) ccdc_set_outaddr(ccdc, buffer->dma); @@ -1829,6 +1856,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, unsigned int width = fmt->width; unsigned int height = fmt->height; struct v4l2_rect *crop; + enum v4l2_field field; unsigned int i; switch (pad) { @@ -1854,6 +1882,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, case CCDC_PAD_SOURCE_OF: pixelcode = fmt->code; + field = fmt->field; *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); /* YUV formats are converted from 2X8 to 1X16 by the bridge and @@ -1878,6 +1907,17 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, crop = __ccdc_get_crop(ccdc, fh, which); fmt->width = crop->width; fmt->height = crop->height; + + /* When input format is interlaced with alternating fields the + * CCDC can interleave the fields. + */ + if (fmt->field == V4L2_FIELD_ALTERNATE && + (field == V4L2_FIELD_INTERLACED_TB || + field == V4L2_FIELD_INTERLACED_BT)) { + fmt->field = field; + fmt->height *= 2; + } + break; case CCDC_PAD_SOURCE_VP: diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index f37a8df23cf6..b5ea8da0b904 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -730,17 +730,13 @@ #define ISPCCDC_HSIZE_OFF_SHIFT 0 -#define ISPCCDC_SDOFST_FINV (1 << 14) -#define ISPCCDC_SDOFST_FOFST_1L 0 -#define ISPCCDC_SDOFST_FOFST_4L (3 << 12) +#define ISPCCDC_SDOFST_FIINV (1 << 14) +#define ISPCCDC_SDOFST_FOFST_SHIFT 12 +#define ISPCCDC_SDOFST_FOFST_MASK (3 << 12) #define ISPCCDC_SDOFST_LOFST3_SHIFT 0 #define ISPCCDC_SDOFST_LOFST2_SHIFT 3 #define ISPCCDC_SDOFST_LOFST1_SHIFT 6 #define ISPCCDC_SDOFST_LOFST0_SHIFT 9 -#define EVENEVEN 1 -#define ODDEVEN 2 -#define EVENODD 3 -#define ODDODD 4 #define ISPCCDC_CLAMP_OBGAIN_SHIFT 0 #define ISPCCDC_CLAMP_OBST_SHIFT 10 diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index c38f1d4cc538..bc38c88c7bd9 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -637,14 +637,40 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) if (format->type != video->type) return -EINVAL; - /* Default to the progressive field order if the requested value is not - * supported (or set to ANY). The only supported orders are progressive - * (available on all video nodes) and alternate (available on capture - * nodes only). - */ - if (format->fmt.pix.field != V4L2_FIELD_ALTERNATE || - video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + /* Replace unsupported field orders with sane defaults. */ + switch (format->fmt.pix.field) { + case V4L2_FIELD_NONE: + /* Progressive is supported everywhere. */ + break; + case V4L2_FIELD_ALTERNATE: + /* ALTERNATE is not supported on output nodes. */ + if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + format->fmt.pix.field = V4L2_FIELD_NONE; + break; + case V4L2_FIELD_INTERLACED: + /* The ISP has no concept of video standard, select the + * top-bottom order when the unqualified interlaced order is + * requested. + */ + format->fmt.pix.field = V4L2_FIELD_INTERLACED_TB; + /* Fall-through */ + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + /* Interlaced orders are only supported at the CCDC output. */ + if (video != &video->isp->isp_ccdc.video_out) + format->fmt.pix.field = V4L2_FIELD_NONE; + break; + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + default: + /* All other field orders are currently unsupported, default to + * progressive. + */ format->fmt.pix.field = V4L2_FIELD_NONE; + break; + } /* Fill the bytesperline and sizeimage fields by converting to media bus * format and back to pixel format. -- GitLab From 9de7af4d5bbff7998c09e854b2999359ac1b2721 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 20 May 2014 14:18:53 -0300 Subject: [PATCH 0510/5088] [media] omap3isp: ccdc: Add support for BT.656 YUV format at the CCDC input Query the CCDC input media bus type from the subdev connected to the CCDC sink pad and configure the CCDC accordingly to support BT.656 synchronization. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 94 +++++++++++++++++++---- drivers/media/platform/omap3isp/ispccdc.h | 2 + 2 files changed, 80 insertions(+), 16 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 8d1861d948d0..150bbf070bf2 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -970,10 +970,16 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 || format->code == V4L2_MBUS_FMT_UYVY8_2X8) { - /* The bridge is enabled for YUV8 formats. Configure the input - * mode accordingly. + /* According to the OMAP3 TRM the input mode only affects SYNC + * mode, enabling BT.656 mode should take precedence. However, + * in practice setting the input mode to YCbCr data on 8 bits + * seems to be required in BT.656 mode. In SYNC mode set it to + * YCbCr on 16 bits as the bridge is enabled in that case. */ - syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16; + if (ccdc->bt656) + syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR8; + else + syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16; } switch (data_size) { @@ -997,7 +1003,10 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, if (pdata && pdata->hs_pol) syn_mode |= ISPCCDC_SYN_MODE_HDPOL; - if (pdata && pdata->vs_pol) + /* The polarity of the vertical sync signal output by the BT.656 + * decoder is not documented and seems to be active low. + */ + if ((pdata && pdata->vs_pol) || ccdc->bt656) syn_mode |= ISPCCDC_SYN_MODE_VDPOL; if (pdata && pdata->fld_pol) @@ -1015,8 +1024,16 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_Y8POS); - isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, - ISPCCDC_REC656IF_R656ON); + /* Enable or disable BT.656 mode, including error correction for the + * synchronization codes. + */ + if (ccdc->bt656) + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, + ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, + ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH); + } /* CCDC formats descriptions */ @@ -1107,20 +1124,32 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) unsigned long flags; unsigned int bridge; unsigned int shift; + unsigned int nph; + unsigned int sph; u32 syn_mode; u32 ccdc_pattern; + ccdc->bt656 = false; + pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); - if (ccdc->input == CCDC_INPUT_PARALLEL) + if (ccdc->input == CCDC_INPUT_PARALLEL) { + struct v4l2_mbus_config cfg; + int ret; + + ret = v4l2_subdev_call(sensor, video, g_mbus_config, &cfg); + if (!ret) + ccdc->bt656 = cfg.type == V4L2_MBUS_BT656; + pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) ->bus.parallel; + } /* CCDC_PAD_SINK */ format = &ccdc->formats[CCDC_PAD_SINK]; /* Compute the lane shifter shift value and enable the bridge when the - * input format is YUV. + * input format is a non-BT.656 YUV variant. */ fmt_src.pad = pad->index; fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; @@ -1133,7 +1162,9 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) depth_out = fmt_info->width; shift = depth_in - depth_out; - if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8) + if (ccdc->bt656) + bridge = ISPCTRL_PAR_BRIDGE_DISABLE; + else if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8) bridge = ISPCTRL_PAR_BRIDGE_LENDIAN; else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8) bridge = ISPCTRL_PAR_BRIDGE_BENDIAN; @@ -1194,10 +1225,24 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) format = &ccdc->formats[CCDC_PAD_SOURCE_OF]; crop = &ccdc->crop; - isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) | - ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT), + /* The horizontal coordinates are expressed in pixel clock cycles. We + * need two cycles per pixel in BT.656 mode, and one cycle per pixel in + * SYNC mode regardless of the format as the bridge is enabled for YUV + * formats in that case. + */ + if (ccdc->bt656) { + sph = crop->left * 2; + nph = crop->width * 2 - 1; + } else { + sph = crop->left; + nph = crop->width - 1; + } + + isp_reg_writel(isp, (sph << ISPCCDC_HORZ_INFO_SPH_SHIFT) | + (nph << ISPCCDC_HORZ_INFO_NPH_SHIFT), OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO); - isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT, + isp_reg_writel(isp, (crop->top << ISPCCDC_VERT_START_SLV0_SHIFT) | + (crop->top << ISPCCDC_VERT_START_SLV1_SHIFT), OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START); isp_reg_writel(isp, (crop->height - 1) << ISPCCDC_VERT_LINES_NLV_SHIFT, @@ -1225,8 +1270,11 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_BSWD); - /* Use PACK8 mode for 1byte per pixel formats. */ - if (omap3isp_video_format_info(format->code)->width <= 8) + /* Use PACK8 mode for 1byte per pixel formats. Check for BT.656 mode + * explicitly as the driver reports 1X16 instead of 2X8 at the OF pad + * for simplicity. + */ + if (omap3isp_video_format_info(format->code)->width <= 8 || ccdc->bt656) syn_mode |= ISPCCDC_SYN_MODE_PACK8; else syn_mode &= ~ISPCCDC_SYN_MODE_PACK8; @@ -1598,6 +1646,16 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) { unsigned long flags; + /* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus + * need to increment the frame counter here. + */ + if (ccdc->bt656) { + struct isp_pipeline *pipe = + to_isp_pipeline(&ccdc->subdev.entity); + + atomic_inc(&pipe->frame_number); + } + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); /* @@ -1885,8 +1943,12 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, field = fmt->field; *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); - /* YUV formats are converted from 2X8 to 1X16 by the bridge and - * can be byte-swapped. + /* In SYNC mode the bridge converts YUV formats from 2X8 to + * 1X16. In BT.656 no such conversion occurs. As we don't know + * at this point whether the source will use SYNC or BT.656 mode + * let's pretend the conversion always occurs. The CCDC will be + * configured to pack bytes in BT.656, hiding the inaccuracy. + * In all cases bytes can be swapped. */ if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 || fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) { diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index dd999be7f82e..c325b8901159 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -113,6 +113,7 @@ struct ispccdc_lsc { * @lsc: Lens shading compensation configuration * @update: Bitmask of controls to update during the next interrupt * @shadow_update: Controls update in progress by userspace + * @bt656: Whether the input interface uses BT.656 synchronization * @underrun: A buffer underrun occurred and a new buffer has been queued * @state: Streaming state * @lock: Serializes shadow_update with interrupt handler @@ -141,6 +142,7 @@ struct isp_ccdc_device { unsigned int update; unsigned int shadow_update; + bool bt656; unsigned int underrun:1; enum isp_pipeline_stream_state state; spinlock_t lock; -- GitLab From aec2de0e93e34e27ef60e7a8f48bc68ec4b4fcbb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 11:51:34 -0300 Subject: [PATCH 0511/5088] [media] omap3isp: ccdc: Disable the video port when unused The video port doesn't support YUV formats. Disable it when the CCDC sink pad format is set to YUV instead of leaving it enabled and relying on downstream modules not to process data they receive from the video port. Experiments showed that this fixes some of the CCDC failures to stop, especially in BT.656 mode. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 70 ++++++++++------------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 150bbf070bf2..ecc37f2d6a90 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -808,29 +808,48 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc) struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); struct isp_device *isp = to_isp_device(ccdc); const struct isp_format_info *info; + struct v4l2_mbus_framefmt *format; unsigned long l3_ick = pipe->l3_ick; unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8; unsigned int div = 0; - u32 fmtcfg_vp; + u32 fmtcfg = ISPCCDC_FMTCFG_VPEN; + + format = &ccdc->formats[CCDC_PAD_SOURCE_VP]; + + if (!format->code) { + /* Disable the video port when the input format isn't supported. + * This is indicated by a pixel code set to 0. + */ + isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG); + return; + } + + isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) | + (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ); + isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) | + ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT); - fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG) - & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK); + isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) | + (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT); info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code); switch (info->width) { case 8: case 10: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0; + fmtcfg |= ISPCCDC_FMTCFG_VPIN_9_0; break; case 11: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1; + fmtcfg |= ISPCCDC_FMTCFG_VPIN_10_1; break; case 12: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2; + fmtcfg |= ISPCCDC_FMTCFG_VPIN_11_2; break; case 13: - fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3; + fmtcfg |= ISPCCDC_FMTCFG_VPIN_12_3; break; } @@ -840,24 +859,9 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc) div = l3_ick / pipe->external_rate; div = clamp(div, 2U, max_div); - fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT; + fmtcfg |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT; - isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG); -} - -/* - * ccdc_enable_vp - Enable Video Port. - * @ccdc: Pointer to ISP CCDC device. - * @enable: 0 Disables VP, 1 Enables VP - * - * This is needed for outputting image to Preview, H3A and HIST ISP submodules. - */ -static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable) -{ - struct isp_device *isp = to_isp_device(ccdc); - - isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG, - ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0); + isp_reg_writel(isp, fmtcfg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG); } /* @@ -1282,18 +1286,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); /* CCDC_PAD_SOURCE_VP */ - format = &ccdc->formats[CCDC_PAD_SOURCE_VP]; - - isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) | - (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ); - isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) | - ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT); - - isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) | - (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT), - OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT); + ccdc_config_vp(ccdc); /* Lens shading correction. */ spin_lock_irqsave(&ccdc->lsc.req_lock, flags); @@ -1837,11 +1830,6 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable) ccdc_configure(ccdc); - /* TODO: Don't configure the video port if all of its output - * links are inactive. - */ - ccdc_config_vp(ccdc); - ccdc_enable_vp(ccdc, 1); ccdc_print_status(ccdc); } -- GitLab From 93d7badf1b929120cbc886f3dfec3ca55549d086 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 7 Jun 2014 20:57:07 -0300 Subject: [PATCH 0512/5088] [media] omap3isp: ccdc: Only complete buffer when all fields are captured Checking that the captured field corresponds to the last required field depending on the requested field order before completing the buffer isn't enough. When the first field at stream start corresponds to the last required field, this would result in returning an interlaced buffer containing a single field. Fix this by keeping track of the fields captured in the buffer, and make sure that both fields are present for alternate field orders. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 78 +++++++++++++++-------- drivers/media/platform/omap3isp/ispccdc.h | 7 ++ 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index ecc37f2d6a90..56c3129c3dcd 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1134,6 +1134,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) u32 ccdc_pattern; ccdc->bt656 = false; + ccdc->fields = 0; pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); @@ -1529,12 +1530,59 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events) spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); } +/* + * Check whether the CCDC has captured all fields necessary to complete the + * buffer. + */ +static bool ccdc_has_all_fields(struct isp_ccdc_device *ccdc) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); + struct isp_device *isp = to_isp_device(ccdc); + enum v4l2_field of_field = ccdc->formats[CCDC_PAD_SOURCE_OF].field; + enum v4l2_field field; + + /* When the input is progressive fields don't matter. */ + if (of_field == V4L2_FIELD_NONE) + return true; + + /* Read the current field identifier. */ + field = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE) + & ISPCCDC_SYN_MODE_FLDSTAT + ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; + + /* When capturing fields in alternate order just store the current field + * identifier in the pipeline. + */ + if (of_field == V4L2_FIELD_ALTERNATE) { + pipe->field = field; + return true; + } + + /* The format is interlaced. Make sure we've captured both fields. */ + ccdc->fields |= field == V4L2_FIELD_BOTTOM + ? CCDC_FIELD_BOTTOM : CCDC_FIELD_TOP; + + if (ccdc->fields != CCDC_FIELD_BOTH) + return false; + + /* Verify that the field just captured corresponds to the last field + * needed based on the desired field order. + */ + if ((of_field == V4L2_FIELD_INTERLACED_TB && field == V4L2_FIELD_TOP) || + (of_field == V4L2_FIELD_INTERLACED_BT && field == V4L2_FIELD_BOTTOM)) + return false; + + /* The buffer can be completed, reset the fields for the next buffer. */ + ccdc->fields = 0; + + return true; +} + static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) { struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); struct isp_device *isp = to_isp_device(ccdc); struct isp_buffer *buffer; - enum v4l2_field field; /* The CCDC generates VD0 interrupts even when disabled (the datasheet * doesn't explicitly state if that's supposed to happen or not, so it @@ -1554,11 +1602,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 1; } - /* Read the current field identifier. */ - field = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE) - & ISPCCDC_SYN_MODE_FLDSTAT - ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; - /* Wait for the CCDC to become idle. */ if (ccdc_sbl_wait_idle(ccdc, 1000)) { dev_info(isp->dev, "CCDC won't become idle!\n"); @@ -1567,27 +1610,8 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 0; } - switch (ccdc->formats[CCDC_PAD_SOURCE_OF].field) { - case V4L2_FIELD_ALTERNATE: - /* When capturing fields in alternate order store the current - * field identifier in the pipeline. - */ - pipe->field = field; - break; - - case V4L2_FIELD_INTERLACED_TB: - /* When interleaving fields only complete the buffer after - * capturing the second field. - */ - if (field == V4L2_FIELD_TOP) - return 1; - break; - - case V4L2_FIELD_INTERLACED_BT: - if (field == V4L2_FIELD_BOTTOM) - return 1; - break; - } + if (!ccdc_has_all_fields(ccdc)) + return 1; buffer = omap3isp_video_buffer_next(&ccdc->video_out); if (buffer != NULL) diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index c325b8901159..731ecc768197 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -93,6 +93,10 @@ struct ispccdc_lsc { #define CCDC_PAD_SOURCE_VP 2 #define CCDC_PADS_NUM 3 +#define CCDC_FIELD_TOP 1 +#define CCDC_FIELD_BOTTOM 2 +#define CCDC_FIELD_BOTH 3 + /* * struct isp_ccdc_device - Structure for the CCDC module to store its own * information @@ -114,6 +118,7 @@ struct ispccdc_lsc { * @update: Bitmask of controls to update during the next interrupt * @shadow_update: Controls update in progress by userspace * @bt656: Whether the input interface uses BT.656 synchronization + * @fields: The fields (CCDC_FIELD_*) stored in the current buffer * @underrun: A buffer underrun occurred and a new buffer has been queued * @state: Streaming state * @lock: Serializes shadow_update with interrupt handler @@ -143,6 +148,8 @@ struct isp_ccdc_device { unsigned int shadow_update; bool bt656; + unsigned int fields; + unsigned int underrun:1; enum isp_pipeline_stream_state state; spinlock_t lock; -- GitLab From 8815392a1d190201765682a82ca4c3e6ad03a674 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 7 Jun 2014 20:57:07 -0300 Subject: [PATCH 0513/5088] [media] omap3isp: ccdc: Rename __ccdc_handle_stopping to ccdc_handle_stopping There's no need for a double underscore in the function name, remove it. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 56c3129c3dcd..cd62d29d34c4 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1413,14 +1413,14 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc, return -EBUSY; } -/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence +/* ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence * @ccdc: Pointer to ISP CCDC device. * @event: Pointing which event trigger handler * * Return 1 when the event and stopping request combination is satisfied, * zero otherwise. */ -static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) +static int ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) { int rval = 0; @@ -1502,7 +1502,7 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events) if (ccdc->lsc.state == LSC_STATE_STOPPING) ccdc->lsc.state = LSC_STATE_STOPPED; - if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE)) + if (ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE)) goto done; if (ccdc->lsc.state != LSC_STATE_RECONFIG) @@ -1642,7 +1642,7 @@ static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc) restart = ccdc_isr_buffer(ccdc); spin_lock_irqsave(&ccdc->lock, flags); - if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) { + if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) { spin_unlock_irqrestore(&ccdc->lock, flags); return; } @@ -1702,7 +1702,7 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) break; } - if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1)) + if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1)) goto done; if (ccdc->lsc.request == NULL) -- GitLab From 1c74817405d42572db2071b0b4a9609b487c91a7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 06:15:33 -0300 Subject: [PATCH 0514/5088] [media] omap3isp: ccdc: Simplify ccdc_lsc_is_configured() Use a local variable to avoid the duplicate spin_unlock_irqrestore() call. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index cd62d29d34c4..6a62cb76cd1f 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -481,14 +481,13 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc) { unsigned long flags; + int ret; spin_lock_irqsave(&ccdc->lsc.req_lock, flags); - if (ccdc->lsc.active) { - spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); - return 1; - } + ret = ccdc->lsc.active != NULL; spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); - return 0; + + return ret; } static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc) -- GitLab From fd93c10afe383d7c28b5edffa29f92b6dae55191 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 09:16:08 -0300 Subject: [PATCH 0515/5088] [media] omap3isp: ccdc: Increment the frame number at VD0 time for BT.656 We will stop using VD1 in BT.656 mode, move frame number increment to the VD0 interrupt handler. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 6a62cb76cd1f..112bced5af99 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1637,6 +1637,16 @@ static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc) unsigned long flags; int restart = 0; + /* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus + * need to increment the frame counter here. + */ + if (ccdc->bt656) { + struct isp_pipeline *pipe = + to_isp_pipeline(&ccdc->subdev.entity); + + atomic_inc(&pipe->frame_number); + } + if (ccdc->output & CCDC_OUTPUT_MEMORY) restart = ccdc_isr_buffer(ccdc); @@ -1662,16 +1672,6 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) { unsigned long flags; - /* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus - * need to increment the frame counter here. - */ - if (ccdc->bt656) { - struct isp_pipeline *pipe = - to_isp_pipeline(&ccdc->subdev.entity); - - atomic_inc(&pipe->frame_number); - } - spin_lock_irqsave(&ccdc->lsc.req_lock, flags); /* -- GitLab From 93456527b4488510d87a523028b3bb73dfdd7669 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 09:41:57 -0300 Subject: [PATCH 0516/5088] [media] omap3isp: ccdc: Fix freeze when a short frame is received In BT.656 mode the synchronization signals are generated by the CCDC from the embedded sync codes. The VD0 and VD1 interrupts are thus only triggered when the CCDC is enabled, unlike external sync mode where the line counter runs even when the CCDC is stopped. We can't disable the CCDC at VD1 time, as no VD0 interrupt would be generated for a short frame, which would result in the CCDC being stopped and no VD interrupt generated anymore. The CCDC is stopped from the VD0 interrupt handler instead for BT.656. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 29 +++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 112bced5af99..ff2ea2bf31e4 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1647,10 +1647,27 @@ static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc) atomic_inc(&pipe->frame_number); } + /* Emulate a VD1 interrupt for BT.656 mode, as we can't stop the CCDC in + * the VD1 interrupt handler in that mode without risking a CCDC stall + * if a short frame is received. + */ + if (ccdc->bt656) { + spin_lock_irqsave(&ccdc->lock, flags); + if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && + ccdc->output & CCDC_OUTPUT_MEMORY) { + if (ccdc->lsc.state != LSC_STATE_STOPPED) + __ccdc_lsc_enable(ccdc, 0); + __ccdc_enable(ccdc, 0); + } + ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1); + spin_unlock_irqrestore(&ccdc->lock, flags); + } + if (ccdc->output & CCDC_OUTPUT_MEMORY) restart = ccdc_isr_buffer(ccdc); spin_lock_irqsave(&ccdc->lock, flags); + if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) { spin_unlock_irqrestore(&ccdc->lock, flags); return; @@ -1672,6 +1689,18 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) { unsigned long flags; + /* In BT.656 mode the synchronization signals are generated by the CCDC + * from the embedded sync codes. The VD0 and VD1 interrupts are thus + * only triggered when the CCDC is enabled, unlike external sync mode + * where the line counter runs even when the CCDC is stopped. We can't + * disable the CCDC at VD1 time, as no VD0 interrupt would be generated + * for a short frame, which would result in the CCDC being stopped and + * no VD interrupt generated anymore. The CCDC is stopped from the VD0 + * interrupt handler instead for BT.656. + */ + if (ccdc->bt656) + return; + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); /* -- GitLab From 0b3fcd5727e835c60de46d33b2f5f5803c4a5de7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 10:26:28 -0300 Subject: [PATCH 0517/5088] [media] omap3isp: ccdc: Don't timeout on stream off when the CCDC is stopped When the CCDC is already stopped due to a buffer underrun, the stop state machine won't advance in BT.656 mode as no interrupt are generated by the stopped CCDC in that mode. Handle this case explicitly in the ccdc_disable() function. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 4 ++++ drivers/media/platform/omap3isp/ispccdc.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index ff2ea2bf31e4..ec0a0e884c79 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1320,6 +1320,8 @@ static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable) isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR, ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0); + + ccdc->running = enable; } static int ccdc_disable(struct isp_ccdc_device *ccdc) @@ -1330,6 +1332,8 @@ static int ccdc_disable(struct isp_ccdc_device *ccdc) spin_lock_irqsave(&ccdc->lock, flags); if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS) ccdc->stopping = CCDC_STOP_REQUEST; + if (!ccdc->running) + ccdc->stopping = CCDC_STOP_FINISHED; spin_unlock_irqrestore(&ccdc->lock, flags); ret = wait_event_timeout(ccdc->wait, diff --git a/drivers/media/platform/omap3isp/ispccdc.h b/drivers/media/platform/omap3isp/ispccdc.h index 731ecc768197..3440a7097940 100644 --- a/drivers/media/platform/omap3isp/ispccdc.h +++ b/drivers/media/platform/omap3isp/ispccdc.h @@ -124,6 +124,7 @@ struct ispccdc_lsc { * @lock: Serializes shadow_update with interrupt handler * @wait: Wait queue used to stop the module * @stopping: Stopping state + * @running: Is the CCDC hardware running * @ioctl_lock: Serializes ioctl calls and LSC requests freeing */ struct isp_ccdc_device { @@ -155,6 +156,7 @@ struct isp_ccdc_device { spinlock_t lock; wait_queue_head_t wait; unsigned int stopping; + bool running; struct mutex ioctl_lock; }; -- GitLab From ca84ea49f8cba11aaca9c9d570431abb5288f56b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 10 Jun 2014 10:28:48 -0300 Subject: [PATCH 0518/5088] [media] omap3isp: ccdc: Restart the CCDC immediately after an underrun in BT.656 As the CCDC doesn't generate interrupts when stopped in BT.656 mode, restart it immediately when the next buffer after an underrun is queued instead of relying on the interrupt handler to restart the CCDC. Signed-off-by: Laurent Pinchart Tested-by: Enrico Butera Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index ec0a0e884c79..cabf46b4b645 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1789,6 +1789,8 @@ int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events) static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) { struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc; + unsigned long flags; + bool restart = false; if (!(ccdc->output & CCDC_OUTPUT_MEMORY)) return -ENODEV; @@ -1797,9 +1799,20 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) /* We now have a buffer queued on the output, restart the pipeline * on the next CCDC interrupt if running in continuous mode (or when - * starting the stream). + * starting the stream) in external sync mode, or immediately in BT.656 + * sync mode as no CCDC interrupt is generated when the CCDC is stopped + * in that case. */ - ccdc->underrun = 1; + spin_lock_irqsave(&ccdc->lock, flags); + if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && !ccdc->running && + ccdc->bt656) + restart = 1; + else + ccdc->underrun = 1; + spin_unlock_irqrestore(&ccdc->lock, flags); + + if (restart) + ccdc_enable(ccdc); return 0; } -- GitLab From 41316a27ee96b31970175bec87210075752001fb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 23 Jul 2014 10:30:57 -0300 Subject: [PATCH 0519/5088] [media] omap3isp: resizer: Remove needless variable initializations There's no need to initialize local variables to zero when they're explicitly assigned another value right after. Remove the needless initializations. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispresizer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 93104b0957b3..06d4e422b5e8 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -229,7 +229,7 @@ static void resizer_set_phase(struct isp_res_device *res, u32 h_phase, u32 v_phase) { struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; + u32 rgval; rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK); @@ -265,7 +265,7 @@ static void resizer_set_luma(struct isp_res_device *res, struct resizer_luma_yenh *luma) { struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; + u32 rgval; rgval = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT) & ISPRSZ_YENH_ALGO_MASK; @@ -312,7 +312,7 @@ static void resizer_set_ratio(struct isp_res_device *res, { struct isp_device *isp = to_isp_device(res); const u16 *h_filter, *v_filter; - u32 rgval = 0; + u32 rgval; rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK); @@ -355,7 +355,7 @@ static void resizer_set_output_size(struct isp_res_device *res, u32 width, u32 height) { struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; + u32 rgval; dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height); rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT) @@ -399,7 +399,7 @@ static void resizer_set_output_offset(struct isp_res_device *res, u32 offset) static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top) { struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; + u32 rgval; rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT) & ISPRSZ_IN_START_HORZ_ST_MASK; @@ -419,7 +419,7 @@ static void resizer_set_input_size(struct isp_res_device *res, u32 width, u32 height) { struct isp_device *isp = to_isp_device(res); - u32 rgval = 0; + u32 rgval; dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height); -- GitLab From d903a0a367f3e0350a3ba1455c0a7c533977fb42 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 23 Jul 2014 10:30:57 -0300 Subject: [PATCH 0520/5088] [media] omap3isp: resizer: Remove slow debugging message from interrupt handler The resizer_set_input_size() function prints a debugging message with the input width and height values. As the function is called from interrupt context, printing that message to the serial console could slow down the interrupt handler and cause it to miss the start of the next frame, causing image corruption. Fix this by reorganizing the resizer debug messages. The driver now prints the input size, the crop rectangle and the output size in the set selection handler instead of scattering debug messages in various places. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispresizer.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 06d4e422b5e8..ebc812e48fe8 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -357,7 +357,6 @@ static void resizer_set_output_size(struct isp_res_device *res, struct isp_device *isp = to_isp_device(res); u32 rgval; - dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height); rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT) & ISPRSZ_OUT_SIZE_HORZ_MASK; rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT) @@ -421,8 +420,6 @@ static void resizer_set_input_size(struct isp_res_device *res, struct isp_device *isp = to_isp_device(res); u32 rgval; - dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height); - rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT) & ISPRSZ_IN_SIZE_HORZ_MASK; rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT) @@ -1292,12 +1289,10 @@ static int resizer_set_selection(struct v4l2_subdev *sd, format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which); - dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__, - sel->r.left, sel->r.top, sel->r.width, sel->r.height, - sel->which); - - dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__, + dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", + __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act", format_sink->width, format_sink->height, + sel->r.left, sel->r.top, sel->r.width, sel->r.height, format_source->width, format_source->height); /* Clamp the crop rectangle to the bounds, and then mangle it further to @@ -1312,6 +1307,12 @@ static int resizer_set_selection(struct v4l2_subdev *sd, *__resizer_get_crop(res, fh, sel->which) = sel->r; resizer_calc_ratios(res, &sel->r, format_source, &ratio); + dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", + __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act", + format_sink->width, format_sink->height, + sel->r.left, sel->r.top, sel->r.width, sel->r.height, + format_source->width, format_source->height); + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) return 0; -- GitLab From cd73bb6c4e493cbe227f7861d96dd864a71fe5bc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 23 Jul 2014 10:30:57 -0300 Subject: [PATCH 0521/5088] [media] omap3isp: resizer: Protect against races when updating crop When updating the crop rectangle during streaming, the IRQ handler will reprogram the resizer after the current frame. A race condition currently exists between the set selection operation and the IRQ handler: if the set selection operation is called twice in a row and the IRQ handler runs only during the second call, it could reprogram the hardware with partially updated values. Use a spinlock to protect against that. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispresizer.c | 43 ++++++++++++++------ drivers/media/platform/omap3isp/ispresizer.h | 3 ++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index ebc812e48fe8..05d1ace57451 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -1062,10 +1062,13 @@ static void resizer_isr_buffer(struct isp_res_device *res) void omap3isp_resizer_isr(struct isp_res_device *res) { struct v4l2_mbus_framefmt *informat, *outformat; + unsigned long flags; if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping)) return; + spin_lock_irqsave(&res->lock, flags); + if (res->applycrop) { outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE, V4L2_SUBDEV_FORMAT_ACTIVE); @@ -1075,6 +1078,8 @@ void omap3isp_resizer_isr(struct isp_res_device *res) res->applycrop = 0; } + spin_unlock_irqrestore(&res->lock, flags); + resizer_isr_buffer(res); } @@ -1277,8 +1282,10 @@ static int resizer_set_selection(struct v4l2_subdev *sd, { struct isp_res_device *res = v4l2_get_subdevdata(sd); struct isp_device *isp = to_isp_device(res); - struct v4l2_mbus_framefmt *format_sink, *format_source; + const struct v4l2_mbus_framefmt *format_sink; + struct v4l2_mbus_framefmt format_source; struct resizer_ratio ratio; + unsigned long flags; if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != RESZ_PAD_SINK) @@ -1286,14 +1293,14 @@ static int resizer_set_selection(struct v4l2_subdev *sd, format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK, sel->which); - format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, - sel->which); + format_source = *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, + sel->which); dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act", format_sink->width, format_sink->height, sel->r.left, sel->r.top, sel->r.width, sel->r.height, - format_source->width, format_source->height); + format_source.width, format_source.height); /* Clamp the crop rectangle to the bounds, and then mangle it further to * fulfill the TRM equations. Store the clamped but otherwise unmangled @@ -1303,29 +1310,39 @@ static int resizer_set_selection(struct v4l2_subdev *sd, * smaller input crop rectangle every time the output size is set if we * stored the mangled rectangle. */ - resizer_try_crop(format_sink, format_source, &sel->r); + resizer_try_crop(format_sink, &format_source, &sel->r); *__resizer_get_crop(res, fh, sel->which) = sel->r; - resizer_calc_ratios(res, &sel->r, format_source, &ratio); + resizer_calc_ratios(res, &sel->r, &format_source, &ratio); dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", __func__, sel->which == V4L2_SUBDEV_FORMAT_TRY ? "try" : "act", format_sink->width, format_sink->height, sel->r.left, sel->r.top, sel->r.width, sel->r.height, - format_source->width, format_source->height); + format_source.width, format_source.height); - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { + *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) = + format_source; return 0; + } + + /* Update the source format, resizing ratios and crop rectangle. If + * streaming is on the IRQ handler will reprogram the resizer after the + * current frame. We thus we need to protect against race conditions. + */ + spin_lock_irqsave(&res->lock, flags); + + *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) = + format_source; res->ratio = ratio; res->crop.active = sel->r; - /* - * set_selection can be called while streaming is on. In this case the - * crop values will be set in the next IRQ. - */ if (res->state != ISP_PIPELINE_STREAM_STOPPED) res->applycrop = 1; + spin_unlock_irqrestore(&res->lock, flags); + return 0; } @@ -1772,6 +1789,8 @@ int omap3isp_resizer_init(struct isp_device *isp) init_waitqueue_head(&res->wait); atomic_set(&res->stopping, 0); + spin_lock_init(&res->lock); + return resizer_init_entities(res); } diff --git a/drivers/media/platform/omap3isp/ispresizer.h b/drivers/media/platform/omap3isp/ispresizer.h index 494f5a2fd4bb..5414542912e2 100644 --- a/drivers/media/platform/omap3isp/ispresizer.h +++ b/drivers/media/platform/omap3isp/ispresizer.h @@ -17,6 +17,7 @@ #ifndef OMAP3_ISP_RESIZER_H #define OMAP3_ISP_RESIZER_H +#include #include /* @@ -86,6 +87,7 @@ enum resizer_input_entity { /* * struct isp_res_device - OMAP3 ISP resizer module + * @lock: Protects formats and crop rectangles between set_selection and IRQ * @crop.request: Crop rectangle requested by the user * @crop.active: Active crop rectangle (based on hardware requirements) */ @@ -106,6 +108,7 @@ struct isp_res_device { enum isp_pipeline_stream_state state; wait_queue_head_t wait; atomic_t stopping; + spinlock_t lock; struct { struct v4l2_rect request; -- GitLab From ae5abd2561b40a1f046088cd30b900ccde63fbc5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:35 -0300 Subject: [PATCH 0522/5088] [media] coda: fix CODA7541 hardware reset Do not try to read the CODA960 GDI status register on CODA7541. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 3a6d1d2b429e..ec82dec04e31 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -350,19 +350,22 @@ static int coda_hw_reset(struct coda_ctx *ctx) idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); - timeout = jiffies + msecs_to_jiffies(100); - coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); - while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { - if (time_after(jiffies, timeout)) - return -ETIME; - cpu_relax(); + if (dev->devtype->product == CODA_960) { + timeout = jiffies + msecs_to_jiffies(100); + coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); + while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { + if (time_after(jiffies, timeout)) + return -ETIME; + cpu_relax(); + } } ret = reset_control_reset(dev->rstc); if (ret < 0) return ret; - coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); + if (dev->devtype->product == CODA_960) + coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); ret = coda_wait_timeout(dev); -- GitLab From 65919e6baa4e6e193dd7e4aa4cfd94b9d69e367e Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:36 -0300 Subject: [PATCH 0523/5088] [media] coda: initialize hardware on pm runtime resume only if firmware available If no firmware was found and the coda module is unloaded, coda_runtime_resume will be called without an allocated code buffer. Do not call coda_hw_init in this case. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index ec82dec04e31..75bdac0d3b07 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -3903,7 +3903,7 @@ static int coda_runtime_resume(struct device *dev) struct coda_dev *cdev = dev_get_drvdata(dev); int ret = 0; - if (dev->pm_domain) { + if (dev->pm_domain && cdev->codebuf.vaddr) { ret = coda_hw_init(cdev); if (ret) v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n"); -- GitLab From 3898e7a72d8131aea2b8daa292df7416a69f41b4 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:37 -0300 Subject: [PATCH 0524/5088] [media] coda: remove CAPTURE and OUTPUT caps This is a mem2mem driver, pure capture or output modes are not supported. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 75bdac0d3b07..6befcfdac15c 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -536,13 +536,7 @@ static int coda_querycap(struct file *file, void *priv, strlcpy(cap->card, coda_product_name(ctx->dev->devtype->product), sizeof(cap->card)); strlcpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info)); - /* - * This is only a mem-to-mem video device. The capture and output - * device capability flags are left only for backward compatibility - * and are scheduled for removal. - */ - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | - V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; -- GitLab From d29a8cf24dca7106f16007e115d3128042e9267a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:38 -0300 Subject: [PATCH 0525/5088] [media] coda: remove VB2_USERPTR from queue io_modes Disallow USERPTR buffers, videobuf2-dma-contig doesn't support them. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 6befcfdac15c..c25756e7eeaf 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -2863,7 +2863,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq, int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &coda_qops; @@ -2876,7 +2876,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq, return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &coda_qops; -- GitLab From 390503bdb49139e83a0cbfd25a31c5fa36db5ca3 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Fri, 18 Jul 2014 07:22:39 -0300 Subject: [PATCH 0526/5088] [media] coda: use CODA_MAX_FRAME_SIZE everywhere Without this changing CODA_MAX_FRAME_SIZE to anything other than 0x100000 can break the bitstram handling Signed-off-by: Michael Olbrich Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index c25756e7eeaf..79c362bd8383 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -3104,7 +3104,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) * by up to 512 bytes */ if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { - if (coda_get_bitstream_payload(ctx) >= 0x100000 - 512) + if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512) kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); } -- GitLab From eabed931dfc3f47f78b93fb49013af6da66682af Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Fri, 18 Jul 2014 07:22:40 -0300 Subject: [PATCH 0527/5088] [media] coda: delay coda_fill_bitstream() coda_fill_bitstream() calls v4l2_m2m_buf_done() which is no longer allowed before streaming was started. Delay coda_fill_bitstream() until coda_start_streaming() and explicitly set 'start_streaming_called' before calling coda_fill_bitstream() Signed-off-by: Michael Olbrich Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 79c362bd8383..898eb3dbb8da 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -1680,7 +1680,8 @@ static void coda_buf_queue(struct vb2_buffer *vb) } mutex_lock(&ctx->bitstream_mutex); v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); - coda_fill_bitstream(ctx); + if (vb2_is_streaming(vb->vb2_queue)) + coda_fill_bitstream(ctx); mutex_unlock(&ctx->bitstream_mutex); } else { v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); @@ -2270,6 +2271,11 @@ 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) { + /* copy the buffers that where queued before streamon */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx); + mutex_unlock(&ctx->bitstream_mutex); + if (coda_get_bitstream_payload(ctx) < 512) return -EINVAL; } else { -- GitLab From 91b5841e24d1ebefd62f03ff790755ae0f379627 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:41 -0300 Subject: [PATCH 0528/5088] [media] coda: lock capture frame size to output frame size when streaming As soon as the output queue is streaming, let try_fmt on the capture side only allow the frame size that was set on the output side. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 898eb3dbb8da..f1cf44a5aa3c 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -719,6 +719,9 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.pixelformat); if (!codec) return -EINVAL; + + f->fmt.pix.width = q_data_src->width; + f->fmt.pix.height = q_data_src->height; } else { /* Otherwise determine codec by encoded format, if possible */ codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, -- GitLab From 121cacf44531666355d44d0f78948818c2ed9aca Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:42 -0300 Subject: [PATCH 0529/5088] [media] coda: split userspace interface into encoder and decoder device Userspace has a hard time making sense of format enumerations on V4L2 mem2mem devices if there are restrictions on which input and output formats can be used together. Alleviate the problem by splitting the video4linux device into separate encoder and decoder devices which list only raw formats on one side and only encoded formats on the other side. With this patch, the instance type (encoder or decoder) is already determined by the open file operation. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 167 ++++++++++++++++++++++++---------- 1 file changed, 120 insertions(+), 47 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index f1cf44a5aa3c..546cc7bd6a71 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -129,7 +129,7 @@ struct coda_aux_buf { struct coda_dev { struct v4l2_device v4l2_dev; - struct video_device vfd; + struct video_device vfd[2]; struct platform_device *plat_dev; const struct coda_devtype *devtype; @@ -1578,14 +1578,22 @@ static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) static void set_default_params(struct coda_ctx *ctx) { + u32 src_fourcc, dst_fourcc; int max_w; int max_h; - ctx->codec = &ctx->dev->devtype->codecs[0]; + if (ctx->inst_type == CODA_INST_ENCODER) { + src_fourcc = V4L2_PIX_FMT_YUV420; + dst_fourcc = V4L2_PIX_FMT_H264; + } else { + src_fourcc = V4L2_PIX_FMT_H264; + dst_fourcc = V4L2_PIX_FMT_YUV420; + } + ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc); max_w = ctx->codec->max_w; max_h = ctx->codec->max_h; - ctx->params.codec_mode = CODA_MODE_INVALID; + ctx->params.codec_mode = ctx->codec->mode; ctx->colorspace = V4L2_COLORSPACE_REC709; ctx->params.framerate = 30; ctx->aborting = 0; @@ -1595,12 +1603,19 @@ static void set_default_params(struct coda_ctx *ctx) ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc; ctx->q_data[V4L2_M2M_SRC].width = max_w; ctx->q_data[V4L2_M2M_SRC].height = max_h; - ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; - ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2; ctx->q_data[V4L2_M2M_DST].width = max_w; ctx->q_data[V4L2_M2M_DST].height = max_h; - ctx->q_data[V4L2_M2M_DST].bytesperline = 0; - ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE; + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) { + ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; + ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2; + ctx->q_data[V4L2_M2M_DST].bytesperline = 0; + ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE; + } else { + ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; + ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE; + ctx->q_data[V4L2_M2M_DST].bytesperline = max_w; + ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2; + } ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; ctx->q_data[V4L2_M2M_DST].rect.width = max_w; @@ -2287,11 +2302,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) } ctx->streamon_out = 1; - - if (coda_format_is_yuv(q_data_src->fourcc)) - ctx->inst_type = CODA_INST_ENCODER; - else - ctx->inst_type = CODA_INST_DECODER; } else { if (count < 1) return -EINVAL; @@ -2713,7 +2723,7 @@ static void coda_stop_streaming(struct vb2_queue *q) } } -static struct vb2_ops coda_qops = { +static const struct vb2_ops coda_qops = { .queue_setup = coda_queue_setup, .buf_prepare = coda_buf_prepare, .buf_queue = coda_buf_queue, @@ -2865,35 +2875,55 @@ static int coda_ctrls_setup(struct coda_ctx *ctx) return v4l2_ctrl_handler_setup(&ctx->ctrls); } -static int coda_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) +static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) +{ + vq->drv_priv = ctx; + vq->ops = &coda_qops; + vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + vq->lock = &ctx->dev->dev_mutex; + + return vb2_queue_init(vq); +} + +static int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) { - struct coda_ctx *ctx = priv; int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; src_vq->io_modes = VB2_DMABUF | VB2_MMAP; - src_vq->drv_priv = ctx; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->ops = &coda_qops; src_vq->mem_ops = &vb2_dma_contig_memops; - src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = &ctx->dev->dev_mutex; - ret = vb2_queue_init(src_vq); + ret = coda_queue_init(priv, src_vq); if (ret) return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; - dst_vq->drv_priv = ctx; - dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->ops = &coda_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = &ctx->dev->dev_mutex; - return vb2_queue_init(dst_vq); + return coda_queue_init(priv, dst_vq); +} + +static int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; + src_vq->mem_ops = &vb2_dma_contig_memops; + + ret = coda_queue_init(priv, src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->mem_ops = &vb2_dma_contig_memops; + + return coda_queue_init(priv, dst_vq); } static int coda_next_free_instance(struct coda_dev *dev) @@ -2907,8 +2937,10 @@ static int coda_next_free_instance(struct coda_dev *dev) return idx; } -static int coda_open(struct file *file) +static int coda_open(struct file *file, enum coda_inst_type inst_type) { + int (*queue_init)(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); struct coda_dev *dev = video_drvdata(file); struct coda_ctx *ctx = NULL; char *name; @@ -2930,6 +2962,7 @@ static int coda_open(struct file *file) ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); kfree(name); + ctx->inst_type = inst_type; init_completion(&ctx->completion); INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); INIT_WORK(&ctx->seq_end_work, coda_seq_end_work); @@ -2963,8 +2996,11 @@ static int coda_open(struct file *file) goto err_clk_ahb; set_default_params(ctx); - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, - &coda_queue_init); + if (inst_type == CODA_INST_ENCODER) + queue_init = coda_encoder_queue_init; + else + queue_init = coda_decoder_queue_init; + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, queue_init); if (IS_ERR(ctx->fh.m2m_ctx)) { ret = PTR_ERR(ctx->fh.m2m_ctx); @@ -3035,6 +3071,16 @@ static int coda_open(struct file *file) return ret; } +static int coda_encoder_open(struct file *file) +{ + return coda_open(file, CODA_INST_ENCODER); +} + +static int coda_decoder_open(struct file *file) +{ + return coda_open(file, CODA_INST_DECODER); +} + static int coda_release(struct file *file) { struct coda_dev *dev = video_drvdata(file); @@ -3079,9 +3125,18 @@ static int coda_release(struct file *file) return 0; } -static const struct v4l2_file_operations coda_fops = { +static const struct v4l2_file_operations coda_encoder_fops = { .owner = THIS_MODULE, - .open = coda_open, + .open = coda_encoder_open, + .release = coda_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct v4l2_file_operations coda_decoder_fops = { + .owner = THIS_MODULE, + .open = coda_decoder_open, .release = coda_release, .poll = v4l2_m2m_fop_poll, .unlocked_ioctl = video_ioctl2, @@ -3564,6 +3619,17 @@ static int coda_check_firmware(struct coda_dev *dev) return ret; } +static int coda_register_device(struct coda_dev *dev, struct video_device *vfd) +{ + vfd->release = video_device_release_empty, + vfd->lock = &dev->dev_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; + video_set_drvdata(vfd, dev); + + return video_register_device(vfd, VFL_TYPE_GRABBER, 0); +} + static void coda_fw_callback(const struct firmware *fw, void *context) { struct coda_dev *dev = context; @@ -3620,15 +3686,6 @@ static void coda_fw_callback(const struct firmware *fw, void *context) return; } - dev->vfd.fops = &coda_fops, - dev->vfd.ioctl_ops = &coda_ioctl_ops; - dev->vfd.release = video_device_release_empty, - dev->vfd.lock = &dev->dev_mutex; - dev->vfd.v4l2_dev = &dev->v4l2_dev; - dev->vfd.vfl_dir = VFL_DIR_M2M; - snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME); - video_set_drvdata(&dev->vfd, dev); - dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); if (IS_ERR(dev->alloc_ctx)) { v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n"); @@ -3641,13 +3698,28 @@ static void coda_fw_callback(const struct firmware *fw, void *context) goto rel_ctx; } - ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0); + dev->vfd[0].fops = &coda_encoder_fops, + dev->vfd[0].ioctl_ops = &coda_ioctl_ops; + snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder"); + ret = coda_register_device(dev, &dev->vfd[0]); if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + v4l2_err(&dev->v4l2_dev, + "Failed to register encoder video device\n"); goto rel_m2m; } - v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n", - dev->vfd.num); + + dev->vfd[1].fops = &coda_decoder_fops, + dev->vfd[1].ioctl_ops = &coda_ioctl_ops; + snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder"); + ret = coda_register_device(dev, &dev->vfd[1]); + if (ret) { + v4l2_err(&dev->v4l2_dev, + "Failed to register decoder video device\n"); + goto rel_m2m; + } + + v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n", + dev->vfd[0].num, dev->vfd[1].num); return; @@ -3882,7 +3954,8 @@ static int coda_remove(struct platform_device *pdev) { struct coda_dev *dev = platform_get_drvdata(pdev); - video_unregister_device(&dev->vfd); + video_unregister_device(&dev->vfd[0]); + video_unregister_device(&dev->vfd[1]); if (dev->m2m_dev) v4l2_m2m_release(dev->m2m_dev); pm_runtime_disable(&pdev->dev); -- GitLab From 22e244b813ddd9a290a446ddca24ceca1f78dad2 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:43 -0300 Subject: [PATCH 0530/5088] [media] coda: split format enumeration for encoder end decoder device Let the decoder capture side and encoder output side only list uncompressed formats, and the decoder output and encoder capture side only list compressed formats. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 57 ++++++++++++----------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 546cc7bd6a71..9493cfdb0ae6 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -542,8 +542,8 @@ static int coda_querycap(struct file *file, void *priv, return 0; } -static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, - enum v4l2_buf_type type, int src_fourcc) +static int coda_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { struct coda_ctx *ctx = fh_to_ctx(priv); struct coda_codec *codecs = ctx->dev->devtype->codecs; @@ -552,11 +552,19 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, int num_codecs = ctx->dev->devtype->num_codecs; int num_formats = ARRAY_SIZE(coda_formats); int i, k, num = 0; + bool yuv; + + if (ctx->inst_type == CODA_INST_ENCODER) + yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT); + else + yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); for (i = 0; i < num_formats; i++) { - /* Both uncompressed formats are always supported */ - if (coda_format_is_yuv(formats[i].fourcc) && - !coda_format_is_yuv(src_fourcc)) { + /* Skip either raw or compressed formats */ + if (yuv != coda_format_is_yuv(formats[i].fourcc)) + continue; + /* All uncompressed formats are always supported */ + if (yuv) { if (num == f->index) break; ++num; @@ -564,12 +572,10 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, } /* Compressed formats may be supported, check the codec list */ for (k = 0; k < num_codecs; k++) { - /* if src_fourcc is set, only consider matching codecs */ - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - formats[i].fourcc == codecs[k].dst_fourcc && - (!src_fourcc || src_fourcc == codecs[k].src_fourcc)) + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + formats[i].fourcc == codecs[k].dst_fourcc) break; - if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && formats[i].fourcc == codecs[k].src_fourcc) break; } @@ -584,7 +590,7 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, fmt = &formats[i]; strlcpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - if (!coda_format_is_yuv(fmt->fourcc)) + if (!yuv) f->flags |= V4L2_FMT_FLAG_COMPRESSED; return 0; } @@ -593,31 +599,6 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, return -EINVAL; } -static int coda_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct coda_ctx *ctx = fh_to_ctx(priv); - struct vb2_queue *src_vq; - struct coda_q_data *q_data_src; - - /* If the source format is already fixed, only list matching formats */ - src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - if (vb2_is_streaming(src_vq)) { - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - - return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE, - q_data_src->fourcc); - } - - return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0); -} - -static int coda_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0); -} - static int coda_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { @@ -970,12 +951,12 @@ static int coda_subscribe_event(struct v4l2_fh *fh, static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_querycap = coda_querycap, - .vidioc_enum_fmt_vid_cap = coda_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = coda_enum_fmt, .vidioc_g_fmt_vid_cap = coda_g_fmt, .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = coda_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_out = coda_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_out = coda_enum_fmt, .vidioc_g_fmt_vid_out = coda_g_fmt, .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out, .vidioc_s_fmt_vid_out = coda_s_fmt_vid_out, -- GitLab From 4f31ff010261b9fd232980088bbdbcfcfc4b9318 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:44 -0300 Subject: [PATCH 0531/5088] [media] coda: default to h.264 decoder on invalid formats If the user provides an invalid format, let the decoder device default to h.264. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 9493cfdb0ae6..b18814ebcd20 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -683,7 +683,7 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - struct coda_codec *codec; + struct coda_codec *codec = NULL; struct vb2_queue *src_vq; int ret; @@ -736,6 +736,12 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv, /* Determine codec by encoded format, returns NULL if raw or invalid */ codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, V4L2_PIX_FMT_YUV420); + if (!codec && ctx->inst_type == CODA_INST_DECODER) { + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264, + V4L2_PIX_FMT_YUV420); + if (!codec) + return -EINVAL; + } if (!f->fmt.pix.colorspace) f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; -- GitLab From 814c376255f2fed2c3120f04486f68fe0c286002 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 18 Jul 2014 07:22:45 -0300 Subject: [PATCH 0532/5088] [media] coda: mark constant structures as such The format and codec lists and the ops structures are read-only. Mark them as const. Acked-by: Hans Verkuil Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index b18814ebcd20..594b0c7c4151 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -102,7 +102,7 @@ struct coda_codec { struct coda_devtype { char *firmware; enum coda_product product; - struct coda_codec *codecs; + const struct coda_codec *codecs; unsigned int num_codecs; size_t workbuf_size; size_t tempbuf_size; @@ -225,7 +225,7 @@ struct coda_ctx { u32 sequence_offset; struct coda_q_data q_data[2]; enum coda_inst_type inst_type; - struct coda_codec *codec; + const struct coda_codec *codec; enum v4l2_colorspace colorspace; struct coda_params params; struct v4l2_ctrl_handler ctrls; @@ -390,7 +390,7 @@ static struct coda_q_data *get_q_data(struct coda_ctx *ctx, /* * Array of all formats supported by any version of Coda: */ -static struct coda_fmt coda_formats[] = { +static const struct coda_fmt coda_formats[] = { { .name = "YUV 4:2:0 Planar, YCbCr", .fourcc = V4L2_PIX_FMT_YUV420, @@ -419,19 +419,19 @@ static struct coda_fmt coda_formats[] = { * i.MX6 -> coda960 * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants */ -static struct coda_codec codadx6_codecs[] = { +static const struct coda_codec codadx6_codecs[] = { CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576), }; -static struct coda_codec coda7_codecs[] = { +static const struct coda_codec coda7_codecs[] = { CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080), }; -static struct coda_codec coda9_codecs[] = { +static const struct coda_codec coda9_codecs[] = { CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1080), CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1080), CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), @@ -458,10 +458,10 @@ static u32 coda_format_normalize_yuv(u32 fourcc) return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc; } -static struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc, - int dst_fourcc) +static const struct coda_codec *coda_find_codec(struct coda_dev *dev, + int src_fourcc, int dst_fourcc) { - struct coda_codec *codecs = dev->devtype->codecs; + const struct coda_codec *codecs = dev->devtype->codecs; int num_codecs = dev->devtype->num_codecs; int k; @@ -483,10 +483,10 @@ static struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc, } static void coda_get_max_dimensions(struct coda_dev *dev, - struct coda_codec *codec, + const struct coda_codec *codec, int *max_w, int *max_h) { - struct coda_codec *codecs = dev->devtype->codecs; + const struct coda_codec *codecs = dev->devtype->codecs; int num_codecs = dev->devtype->num_codecs; unsigned int w, h; int k; @@ -546,9 +546,9 @@ static int coda_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - struct coda_codec *codecs = ctx->dev->devtype->codecs; - struct coda_fmt *formats = coda_formats; - struct coda_fmt *fmt; + const struct coda_codec *codecs = ctx->dev->devtype->codecs; + const struct coda_fmt *formats = coda_formats; + const struct coda_fmt *fmt; int num_codecs = ctx->dev->devtype->num_codecs; int num_formats = ARRAY_SIZE(coda_formats); int i, k, num = 0; @@ -621,7 +621,7 @@ static int coda_g_fmt(struct file *file, void *priv, return 0; } -static int coda_try_fmt(struct coda_ctx *ctx, struct coda_codec *codec, +static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, struct v4l2_format *f) { struct coda_dev *dev = ctx->dev; @@ -683,7 +683,7 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - struct coda_codec *codec = NULL; + const struct coda_codec *codec = NULL; struct vb2_queue *src_vq; int ret; @@ -731,7 +731,7 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - struct coda_codec *codec; + const struct coda_codec *codec; /* Determine codec by encoded format, returns NULL if raw or invalid */ codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, @@ -1529,7 +1529,7 @@ static void coda_unlock(void *m2m_priv) mutex_unlock(&pcdev->dev_mutex); } -static struct v4l2_m2m_ops coda_m2m_ops = { +static const struct v4l2_m2m_ops coda_m2m_ops = { .device_run = coda_device_run, .job_ready = coda_job_ready, .job_abort = coda_job_abort, @@ -2799,7 +2799,7 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static struct v4l2_ctrl_ops coda_ctrl_ops = { +static const struct v4l2_ctrl_ops coda_ctrl_ops = { .s_ctrl = coda_s_ctrl, }; -- GitLab From e19a763950fa3598edd488c9bf28c86e79262211 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:38 -0300 Subject: [PATCH 0533/5088] [media] coda: move coda driver into its own directory The coda driver has grown significantly and will continue to grow. Move the coda driver into its own directory so it can be split. Rename coda.h to coda_regs.h as it contains the register defines. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Makefile | 2 +- drivers/media/platform/coda/Makefile | 3 +++ drivers/media/platform/{coda.c => coda/coda-common.c} | 2 +- drivers/media/platform/{coda.h => coda/coda_regs.h} | 0 4 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 drivers/media/platform/coda/Makefile rename drivers/media/platform/{coda.c => coda/coda-common.c} (99%) rename drivers/media/platform/{coda.h => coda/coda_regs.h} (100%) diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index e5269da91906..4ac4c91b4415 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe/ obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o -obj-$(CONFIG_VIDEO_CODA) += coda.o +obj-$(CONFIG_VIDEO_CODA) += coda/ obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile new file mode 100644 index 000000000000..13d9ad6df51f --- /dev/null +++ b/drivers/media/platform/coda/Makefile @@ -0,0 +1,3 @@ +coda-objs := coda-common.o + +obj-$(CONFIG_VIDEO_CODA) += coda.o diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda/coda-common.c similarity index 99% rename from drivers/media/platform/coda.c rename to drivers/media/platform/coda/coda-common.c index 594b0c7c4151..98784ee9d38a 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda/coda-common.c @@ -38,7 +38,7 @@ #include #include -#include "coda.h" +#include "coda_regs.h" #define CODA_NAME "coda" diff --git a/drivers/media/platform/coda.h b/drivers/media/platform/coda/coda_regs.h similarity index 100% rename from drivers/media/platform/coda.h rename to drivers/media/platform/coda/coda_regs.h -- GitLab From a2b3e46acbf1edfc772a15e79ab1dbd20ad55cba Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:39 -0300 Subject: [PATCH 0534/5088] [media] coda: move defines, enums, and structs into shared header These will have to be shared between multiple code files. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 193 +------------------ drivers/media/platform/coda/coda.h | 216 ++++++++++++++++++++++ 2 files changed, 219 insertions(+), 190 deletions(-) create mode 100644 drivers/media/platform/coda/coda.h diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 98784ee9d38a..dc60bbfd6ebc 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -38,6 +38,7 @@ #include #include +#include "coda.h" #include "coda_regs.h" #define CODA_NAME "coda" @@ -50,10 +51,6 @@ #define CODA7_PS_BUF_SIZE 0x28000 #define CODA9_PS_SAVE_SIZE (512 * 1024) -#define CODA_MAX_FRAMEBUFFERS 8 - -#define CODA_MAX_FRAME_SIZE 0x100000 -#define FMO_SLICE_SAVE_BUF_SIZE (32) #define CODA_DEFAULT_GAMMA 4096 #define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ @@ -70,207 +67,23 @@ static int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-1)"); -enum { - V4L2_M2M_SRC = 0, - V4L2_M2M_DST = 1, -}; - -enum coda_inst_type { - CODA_INST_ENCODER, - CODA_INST_DECODER, -}; - -enum coda_product { - CODA_DX6 = 0xf001, - CODA_7541 = 0xf012, - CODA_960 = 0xf020, -}; - struct coda_fmt { char *name; u32 fourcc; }; -struct coda_codec { - u32 mode; - u32 src_fourcc; - u32 dst_fourcc; - u32 max_w; - u32 max_h; -}; - -struct coda_devtype { - char *firmware; - enum coda_product product; - const struct coda_codec *codecs; - unsigned int num_codecs; - size_t workbuf_size; - size_t tempbuf_size; - size_t iram_size; -}; - -/* Per-queue, driver-specific private data */ -struct coda_q_data { - unsigned int width; - unsigned int height; - unsigned int bytesperline; - unsigned int sizeimage; - unsigned int fourcc; - struct v4l2_rect rect; -}; - -struct coda_aux_buf { - void *vaddr; - dma_addr_t paddr; - u32 size; - struct debugfs_blob_wrapper blob; - struct dentry *dentry; -}; - -struct coda_dev { - struct v4l2_device v4l2_dev; - struct video_device vfd[2]; - struct platform_device *plat_dev; - const struct coda_devtype *devtype; - - void __iomem *regs_base; - struct clk *clk_per; - struct clk *clk_ahb; - struct reset_control *rstc; - - struct coda_aux_buf codebuf; - struct coda_aux_buf tempbuf; - struct coda_aux_buf workbuf; - struct gen_pool *iram_pool; - struct coda_aux_buf iram; - - spinlock_t irqlock; - struct mutex dev_mutex; - struct mutex coda_mutex; - struct workqueue_struct *workqueue; - struct v4l2_m2m_dev *m2m_dev; - struct vb2_alloc_ctx *alloc_ctx; - struct list_head instances; - unsigned long instance_mask; - struct dentry *debugfs_root; -}; - -struct coda_params { - u8 rot_mode; - u8 h264_intra_qp; - u8 h264_inter_qp; - u8 h264_min_qp; - u8 h264_max_qp; - u8 h264_deblk_enabled; - u8 h264_deblk_alpha; - u8 h264_deblk_beta; - u8 mpeg4_intra_qp; - u8 mpeg4_inter_qp; - u8 gop_size; - int intra_refresh; - int codec_mode; - int codec_mode_aux; - enum v4l2_mpeg_video_multi_slice_mode slice_mode; - u32 framerate; - u16 bitrate; - u32 slice_max_bits; - u32 slice_max_mb; -}; - -struct coda_iram_info { - u32 axi_sram_use; - phys_addr_t buf_bit_use; - phys_addr_t buf_ip_ac_dc_use; - phys_addr_t buf_dbk_y_use; - phys_addr_t buf_dbk_c_use; - phys_addr_t buf_ovl_use; - phys_addr_t buf_btp_use; - phys_addr_t search_ram_paddr; - int search_ram_size; - int remaining; - 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 -}; - -struct coda_timestamp { - struct list_head list; - u32 sequence; - struct v4l2_timecode timecode; - struct timeval timestamp; -}; - -struct coda_ctx { - struct coda_dev *dev; - struct mutex buffer_mutex; - struct list_head list; - struct work_struct pic_run_work; - struct work_struct seq_end_work; - struct completion completion; - int aborting; - int initialized; - int streamon_out; - int streamon_cap; - u32 isequence; - u32 qsequence; - u32 osequence; - u32 sequence_offset; - struct coda_q_data q_data[2]; - enum coda_inst_type inst_type; - const struct coda_codec *codec; - enum v4l2_colorspace colorspace; - struct coda_params params; - struct v4l2_ctrl_handler ctrls; - struct v4l2_fh fh; - int gopcounter; - int runcounter; - char vpu_header[3][64]; - int vpu_header_size[3]; - struct kfifo bitstream_fifo; - struct mutex bitstream_mutex; - struct coda_aux_buf bitstream; - bool hold; - struct coda_aux_buf parabuf; - struct coda_aux_buf psbuf; - struct coda_aux_buf slicebuf; - struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS]; - u32 frame_types[CODA_MAX_FRAMEBUFFERS]; - struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS]; - u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; - struct list_head timestamp_list; - struct coda_aux_buf workbuf; - int num_internal_frames; - int idx; - int reg_idx; - struct coda_iram_info iram_info; - struct gdi_tiled_map tiled_map; - u32 bit_stream_param; - u32 frm_dis_flg; - u32 frame_mem_ctrl; - int display_idx; - struct dentry *debugfs_entry; -}; - static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; -static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg) +void coda_write(struct coda_dev *dev, u32 data, u32 reg) { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); writel(data, dev->regs_base + reg); } -static inline unsigned int coda_read(struct coda_dev *dev, u32 reg) +unsigned int coda_read(struct coda_dev *dev, u32 reg) { u32 data; data = readl(dev->regs_base + reg); diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h new file mode 100644 index 000000000000..aafd1869004b --- /dev/null +++ b/drivers/media/platform/coda/coda.h @@ -0,0 +1,216 @@ +/* + * Coda multi-standard codec IP + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + * Copyright (C) 2012-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 +#include +#include +#include + +#include +#include +#include +#include + +#include "coda_regs.h" + +#define CODA_MAX_FRAMEBUFFERS 8 +#define CODA_MAX_FRAME_SIZE 0x100000 +#define FMO_SLICE_SAVE_BUF_SIZE (32) + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +enum coda_inst_type { + CODA_INST_ENCODER, + CODA_INST_DECODER, +}; + +enum coda_product { + CODA_DX6 = 0xf001, + CODA_7541 = 0xf012, + CODA_960 = 0xf020, +}; + +struct coda_devtype { + char *firmware; + enum coda_product product; + const struct coda_codec *codecs; + unsigned int num_codecs; + size_t workbuf_size; + size_t tempbuf_size; + size_t iram_size; +}; + +struct coda_aux_buf { + void *vaddr; + dma_addr_t paddr; + u32 size; + struct debugfs_blob_wrapper blob; + struct dentry *dentry; +}; + +struct coda_dev { + struct v4l2_device v4l2_dev; + struct video_device vfd[2]; + struct platform_device *plat_dev; + const struct coda_devtype *devtype; + + void __iomem *regs_base; + struct clk *clk_per; + struct clk *clk_ahb; + struct reset_control *rstc; + + struct coda_aux_buf codebuf; + struct coda_aux_buf tempbuf; + struct coda_aux_buf workbuf; + struct gen_pool *iram_pool; + struct coda_aux_buf iram; + + spinlock_t irqlock; + struct mutex dev_mutex; + struct mutex coda_mutex; + struct workqueue_struct *workqueue; + struct v4l2_m2m_dev *m2m_dev; + struct vb2_alloc_ctx *alloc_ctx; + struct list_head instances; + unsigned long instance_mask; + struct dentry *debugfs_root; +}; + +struct coda_codec { + u32 mode; + u32 src_fourcc; + u32 dst_fourcc; + u32 max_w; + u32 max_h; +}; + +struct coda_huff_tab; + +struct coda_params { + u8 rot_mode; + u8 h264_intra_qp; + u8 h264_inter_qp; + u8 h264_min_qp; + u8 h264_max_qp; + u8 h264_deblk_enabled; + u8 h264_deblk_alpha; + u8 h264_deblk_beta; + u8 mpeg4_intra_qp; + u8 mpeg4_inter_qp; + u8 gop_size; + int intra_refresh; + int codec_mode; + int codec_mode_aux; + enum v4l2_mpeg_video_multi_slice_mode slice_mode; + u32 framerate; + u16 bitrate; + u32 slice_max_bits; + u32 slice_max_mb; +}; + +struct coda_timestamp { + struct list_head list; + u32 sequence; + struct v4l2_timecode timecode; + struct timeval timestamp; +}; + +/* Per-queue, driver-specific private data */ +struct coda_q_data { + unsigned int width; + unsigned int height; + unsigned int bytesperline; + unsigned int sizeimage; + unsigned int fourcc; + struct v4l2_rect rect; +}; + +struct coda_iram_info { + u32 axi_sram_use; + phys_addr_t buf_bit_use; + phys_addr_t buf_ip_ac_dc_use; + phys_addr_t buf_dbk_y_use; + phys_addr_t buf_dbk_c_use; + phys_addr_t buf_ovl_use; + phys_addr_t buf_btp_use; + phys_addr_t search_ram_paddr; + int search_ram_size; + int remaining; + 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 +}; + +struct coda_ctx { + struct coda_dev *dev; + struct mutex buffer_mutex; + struct list_head list; + struct work_struct pic_run_work; + struct work_struct seq_end_work; + struct completion completion; + int aborting; + int initialized; + int streamon_out; + int streamon_cap; + u32 isequence; + u32 qsequence; + u32 osequence; + u32 sequence_offset; + struct coda_q_data q_data[2]; + enum coda_inst_type inst_type; + const struct coda_codec *codec; + enum v4l2_colorspace colorspace; + struct coda_params params; + struct v4l2_ctrl_handler ctrls; + struct v4l2_fh fh; + int gopcounter; + int runcounter; + char vpu_header[3][64]; + int vpu_header_size[3]; + struct kfifo bitstream_fifo; + struct mutex bitstream_mutex; + struct coda_aux_buf bitstream; + bool hold; + struct coda_aux_buf parabuf; + struct coda_aux_buf psbuf; + struct coda_aux_buf slicebuf; + struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS]; + u32 frame_types[CODA_MAX_FRAMEBUFFERS]; + struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS]; + u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; + struct list_head timestamp_list; + struct coda_aux_buf workbuf; + int num_internal_frames; + int idx; + int reg_idx; + struct coda_iram_info iram_info; + struct gdi_tiled_map tiled_map; + u32 bit_stream_param; + u32 frm_dis_flg; + u32 frame_mem_ctrl; + int display_idx; + struct dentry *debugfs_entry; +}; -- GitLab From a1192a17eed8ee30fd0f8d944d66fbe5288641e2 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:40 -0300 Subject: [PATCH 0535/5088] [media] coda: add context ops Add a struct coda_context_ops that encapsulates context specific operations. This will simplify adding JPEG support in the future and helps to avoid exporting all functions individually when they move out of the main code file. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 85 +++++++++++++---------- drivers/media/platform/coda/coda.h | 13 ++++ 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index dc60bbfd6ebc..07c132485d8f 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -800,7 +800,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static int coda_start_decoding(struct coda_ctx *ctx); +static int __coda_start_decoding(struct coda_ctx *ctx); static inline int coda_get_bitstream_payload(struct coda_ctx *ctx) { @@ -976,7 +976,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) /* Run coda_start_decoding (again) if not yet initialized */ if (!ctx->initialized) { - int ret = coda_start_decoding(ctx); + int ret = __coda_start_decoding(ctx); if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); @@ -1041,7 +1041,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) return 0; } -static void coda_prepare_encode(struct coda_ctx *ctx) +static int coda_prepare_encode(struct coda_ctx *ctx) { struct coda_q_data *q_data_src, *q_data_dst; struct vb2_buffer *src_buf, *dst_buf; @@ -1183,6 +1183,8 @@ static void coda_prepare_encode(struct coda_ctx *ctx) ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); } + + return 0; } static void coda_device_run(void *m2m_priv) @@ -1233,16 +1235,12 @@ static void coda_pic_run_work(struct work_struct *work) mutex_lock(&ctx->buffer_mutex); mutex_lock(&dev->coda_mutex); - if (ctx->inst_type == CODA_INST_DECODER) { - ret = coda_prepare_decode(ctx); - if (ret < 0) { - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); - /* job_finish scheduled by prepare_decode */ - return; - } - } else { - coda_prepare_encode(ctx); + ret = ctx->ops->prepare_run(ctx); + if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) { + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); + /* job_finish scheduled by prepare_decode */ + return; } if (dev->devtype->product != CODA_DX6) @@ -1260,10 +1258,7 @@ static void coda_pic_run_work(struct work_struct *work) coda_hw_reset(ctx); } else if (!ctx->aborting) { - if (ctx->inst_type == CODA_INST_DECODER) - coda_finish_decode(ctx); - else - coda_finish_encode(ctx); + ctx->ops->finish_run(ctx); } if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) @@ -1846,7 +1841,7 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx, return ret; } -static int coda_start_decoding(struct coda_ctx *ctx) +static int __coda_start_decoding(struct coda_ctx *ctx) { struct coda_q_data *q_data_src, *q_data_dst; u32 bitstream_buf, bitstream_size; @@ -2037,6 +2032,18 @@ static int coda_start_decoding(struct coda_ctx *ctx) return 0; } +static int coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + int ret; + + mutex_lock(&dev->coda_mutex); + ret = __coda_start_decoding(ctx); + mutex_unlock(&dev->coda_mutex); + + return ret; +} + static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf, int header_code, u8 *header, int *size) { @@ -2081,7 +2088,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) { struct coda_ctx *ctx = vb2_get_drv_priv(q); struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; - struct coda_dev *dev = ctx->dev; struct coda_q_data *q_data_src, *q_data_dst; u32 dst_fourcc; int ret = 0; @@ -2133,16 +2139,12 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) if (ret < 0) return ret; + ret = ctx->ops->start_streaming(ctx); if (ctx->inst_type == CODA_INST_DECODER) { - mutex_lock(&dev->coda_mutex); - ret = coda_start_decoding(ctx); - mutex_unlock(&dev->coda_mutex); if (ret == -EAGAIN) return 0; else if (ret < 0) return ret; - } else { - ret = coda_start_encoding(ctx); } ctx->initialized = 1; @@ -2737,10 +2739,9 @@ static int coda_next_free_instance(struct coda_dev *dev) return idx; } -static int coda_open(struct file *file, enum coda_inst_type inst_type) +static int coda_open(struct file *file, enum coda_inst_type inst_type, + const struct coda_context_ops *ctx_ops) { - int (*queue_init)(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq); struct coda_dev *dev = video_drvdata(file); struct coda_ctx *ctx = NULL; char *name; @@ -2763,9 +2764,10 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type) kfree(name); ctx->inst_type = inst_type; + ctx->ops = ctx_ops; init_completion(&ctx->completion); INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); - INIT_WORK(&ctx->seq_end_work, coda_seq_end_work); + INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); v4l2_fh_init(&ctx->fh, video_devdata(file)); file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); @@ -2796,11 +2798,8 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type) goto err_clk_ahb; set_default_params(ctx); - if (inst_type == CODA_INST_ENCODER) - queue_init = coda_encoder_queue_init; - else - queue_init = coda_decoder_queue_init; - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, queue_init); + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, + ctx->ops->queue_init); if (IS_ERR(ctx->fh.m2m_ctx)) { ret = PTR_ERR(ctx->fh.m2m_ctx); @@ -2871,14 +2870,30 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type) return ret; } +struct coda_context_ops coda_encode_ops = { + .queue_init = coda_encoder_queue_init, + .start_streaming = coda_start_encoding, + .prepare_run = coda_prepare_encode, + .finish_run = coda_finish_encode, + .seq_end_work = coda_seq_end_work, +}; + +struct coda_context_ops coda_decode_ops = { + .queue_init = coda_decoder_queue_init, + .start_streaming = coda_start_decoding, + .prepare_run = coda_prepare_decode, + .finish_run = coda_finish_decode, + .seq_end_work = coda_seq_end_work +}; + static int coda_encoder_open(struct file *file) { - return coda_open(file, CODA_INST_ENCODER); + return coda_open(file, CODA_INST_ENCODER, &coda_encode_ops); } static int coda_decoder_open(struct file *file) { - return coda_open(file, CODA_INST_DECODER); + return coda_open(file, CODA_INST_DECODER, &coda_decode_ops); } static int coda_release(struct file *file) diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index aafd1869004b..c98270c2532a 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -164,6 +164,18 @@ struct gdi_tiled_map { #define GDI_LINEAR_FRAME_MAP 0 }; +struct coda_ctx; + +struct coda_context_ops { + int (*queue_init)(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); + int (*start_streaming)(struct coda_ctx *ctx); + int (*prepare_run)(struct coda_ctx *ctx); + void (*finish_run)(struct coda_ctx *ctx); + void (*seq_end_work)(struct work_struct *work); + void (*release)(struct coda_ctx *ctx); +}; + struct coda_ctx { struct coda_dev *dev; struct mutex buffer_mutex; @@ -171,6 +183,7 @@ struct coda_ctx { struct work_struct pic_run_work; struct work_struct seq_end_work; struct completion completion; + const struct coda_context_ops *ops; int aborting; int initialized; int streamon_out; -- GitLab From 8a82c6ba2e92dbd39cb7e5f46aa40daf3432b967 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:41 -0300 Subject: [PATCH 0536/5088] [media] coda: move BIT processor command execution out of pic_run_work In preparation for the split, move the AXI_SRAM_USE register access and the PIC_RUN command execution out of pic_run_work into prepare_encode/decode. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 07c132485d8f..3e6bcca45be6 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1038,6 +1038,13 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + coda_kfifo_sync_to_device_full(ctx); + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + return 0; } @@ -1184,6 +1191,12 @@ static int coda_prepare_encode(struct coda_ctx *ctx) coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); } + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + return 0; } @@ -1243,14 +1256,6 @@ static void coda_pic_run_work(struct work_struct *work) return; } - if (dev->devtype->product != CODA_DX6) - coda_write(dev, ctx->iram_info.axi_sram_use, - CODA7_REG_BIT_AXI_SRAM_USE); - - if (ctx->inst_type == CODA_INST_DECODER) - coda_kfifo_sync_to_device_full(ctx); - coda_command_async(ctx, CODA_COMMAND_PIC_RUN); - if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n"); -- GitLab From 347bb7f019db8ff52a9285abc6d776c6a776e0e9 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:42 -0300 Subject: [PATCH 0537/5088] [media] coda: add coda_bit_stream_set_flag helper This adds a helper function to consolidate three occurences where the bitstream parameter stream end flag is set during operation. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 52 +++++++++-------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3e6bcca45be6..3e232441549b 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -187,6 +187,20 @@ static int coda_hw_reset(struct coda_ctx *ctx) return ret; } +static void coda_bit_stream_end_flag(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + + if ((dev->devtype->product == CODA_960) && + coda_isbusy(dev) && + (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { + /* If this context is currently running, update the hardware flag */ + coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + } +} + static struct coda_q_data *get_q_data(struct coda_ctx *ctx, enum v4l2_buf_type type) { @@ -730,7 +744,6 @@ static int coda_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { struct coda_ctx *ctx = fh_to_ctx(fh); - struct coda_dev *dev = ctx->dev; int ret; ret = coda_try_decoder_cmd(file, fh, dc); @@ -741,15 +754,8 @@ static int coda_decoder_cmd(struct file *file, void *fh, if (ctx->inst_type != CODA_INST_DECODER) return 0; - /* Set the strem-end flag on this context */ - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - - if ((dev->devtype->product == CODA_960) && - coda_isbusy(dev) && - (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - /* If this context is currently running, update the hardware flag */ - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } + /* Set the stream-end flag on this context */ + coda_bit_stream_end_flag(ctx); ctx->hold = false; v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); @@ -1472,7 +1478,6 @@ static int coda_buf_prepare(struct vb2_buffer *vb) static void coda_buf_queue(struct vb2_buffer *vb) { struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct coda_dev *dev = ctx->dev; struct coda_q_data *q_data; q_data = get_q_data(ctx, vb->vb2_queue->type); @@ -1487,15 +1492,8 @@ static void coda_buf_queue(struct vb2_buffer *vb) * For backwards compatibility, queuing an empty buffer marks * the stream end */ - if (vb2_get_plane_payload(vb, 0) == 0) { - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - if ((dev->devtype->product == CODA_960) && - coda_isbusy(dev) && - (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - /* if this decoder instance is running, set the stream end flag */ - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } - } + if (vb2_get_plane_payload(vb, 0) == 0) + coda_bit_stream_end_flag(ctx); mutex_lock(&ctx->bitstream_mutex); v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); if (vb2_is_streaming(vb->vb2_queue)) @@ -2492,19 +2490,7 @@ static void coda_stop_streaming(struct vb2_queue *q) "%s: output\n", __func__); ctx->streamon_out = 0; - if (ctx->inst_type == CODA_INST_DECODER && - coda_isbusy(dev) && ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX)) { - /* if this decoder instance is running, set the stream end flag */ - if (dev->devtype->product == CODA_960) { - u32 val = coda_read(dev, CODA_REG_BIT_BIT_STREAM_PARAM); - - val |= CODA_BIT_STREAM_END_FLAG; - coda_write(dev, val, CODA_REG_BIT_BIT_STREAM_PARAM); - ctx->bit_stream_param = val; - } - } - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - + coda_bit_stream_end_flag(ctx); ctx->isequence = 0; } else { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, -- GitLab From 58b7677db01585736d2175f385dcfcc313aed3de Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:43 -0300 Subject: [PATCH 0538/5088] [media] coda: move per-instance buffer allocation and cleanup This patch moves the context buffer allocation into the context start_streaming callbacks. The context buffer and internal framebuffer cleanup is moved into the context release callback. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 31 +++++++++++++++-------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3e232441549b..64151aafd21f 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1861,6 +1861,11 @@ static int __coda_start_decoding(struct coda_ctx *ctx) bitstream_size = ctx->bitstream.size; src_fourcc = q_data_src->fourcc; + /* Allocate per-instance buffers */ + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); /* Update coda bitstream read and write pointers from kfifo */ @@ -2137,11 +2142,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) return -EINVAL; } - /* Allocate per-instance buffers */ - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - ret = ctx->ops->start_streaming(ctx); if (ctx->inst_type == CODA_INST_DECODER) { if (ret == -EAGAIN) @@ -2168,6 +2168,11 @@ static int coda_start_encoding(struct coda_ctx *ctx) q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); dst_fourcc = q_data_dst->fourcc; + /* Allocate per-instance buffers */ + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); bitstream_size = q_data_dst->sizeimage; @@ -2838,7 +2843,6 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, return 0; err_dma_writecombine: - coda_free_context_buffers(ctx); if (ctx->dev->devtype->product == CODA_DX6) coda_free_aux_buf(dev, &ctx->workbuf); coda_free_aux_buf(dev, &ctx->parabuf); @@ -2861,12 +2865,19 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, return ret; } +static void coda_bit_release(struct coda_ctx *ctx) +{ + coda_free_framebuffers(ctx); + coda_free_context_buffers(ctx); +} + struct coda_context_ops coda_encode_ops = { .queue_init = coda_encoder_queue_init, .start_streaming = coda_start_encoding, .prepare_run = coda_prepare_encode, .finish_run = coda_finish_encode, .seq_end_work = coda_seq_end_work, + .release = coda_bit_release, }; struct coda_context_ops coda_decode_ops = { @@ -2874,7 +2885,8 @@ struct coda_context_ops coda_decode_ops = { .start_streaming = coda_start_decoding, .prepare_run = coda_prepare_decode, .finish_run = coda_finish_decode, - .seq_end_work = coda_seq_end_work + .seq_end_work = coda_seq_end_work, + .release = coda_bit_release, }; static int coda_encoder_open(struct file *file) @@ -2906,15 +2918,12 @@ static int coda_release(struct file *file) flush_work(&ctx->seq_end_work); } - coda_free_framebuffers(ctx); - coda_lock(ctx); list_del(&ctx->list); coda_unlock(ctx); dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr, ctx->bitstream.paddr); - coda_free_context_buffers(ctx); if (ctx->dev->devtype->product == CODA_DX6) coda_free_aux_buf(dev, &ctx->workbuf); @@ -2926,6 +2935,8 @@ static int coda_release(struct file *file) v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); clear_bit(ctx->idx, &dev->instance_mask); + if (ctx->ops->release) + ctx->ops->release(ctx); kfree(ctx); return 0; -- GitLab From 4f4ee9ee88720e27b2e90e5dc3d9c086b069a316 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:44 -0300 Subject: [PATCH 0539/5088] [media] coda: move H.264 helper function into separate file Currently there is only the coda_h264_padding function, but we will have to add more H.264 specific helpers later. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/Makefile | 2 +- drivers/media/platform/coda/coda-common.c | 22 -------------- drivers/media/platform/coda/coda-h264.c | 36 +++++++++++++++++++++++ drivers/media/platform/coda/coda.h | 2 ++ 4 files changed, 39 insertions(+), 23 deletions(-) create mode 100644 drivers/media/platform/coda/coda-h264.c diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 13d9ad6df51f..0e59fbd06ae6 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,3 +1,3 @@ -coda-objs := coda-common.o +coda-objs := coda-common.o coda-h264.o obj-$(CONFIG_VIDEO_CODA) += coda.o diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 64151aafd21f..574742e1e82c 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -72,10 +72,6 @@ struct coda_fmt { u32 fourcc; }; -static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; -static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; - void coda_write(struct coda_dev *dev, u32 data, u32 reg) { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, @@ -1627,24 +1623,6 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_d return 0; } -static int coda_h264_padding(int size, char *p) -{ - int nal_size; - int diff; - - diff = size - (size & ~0x7); - if (diff == 0) - return 0; - - nal_size = coda_filler_size[diff]; - memcpy(p, coda_filler_nal, nal_size); - - /* Add rbsp stop bit and trailing at the end */ - *(p + nal_size - 1) = 0x80; - - return nal_size; -} - static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) { phys_addr_t ret; diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c new file mode 100644 index 000000000000..0b2fdbeea7cb --- /dev/null +++ b/drivers/media/platform/coda/coda-h264.c @@ -0,0 +1,36 @@ +/* + * Coda multi-standard codec IP - H.264 helper functions + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + * + * 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 + +static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; +static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; + +int coda_h264_padding(int size, char *p) +{ + int nal_size; + int diff; + + diff = size - (size & ~0x7); + if (diff == 0) + return 0; + + nal_size = coda_filler_size[diff]; + memcpy(p, coda_filler_nal, nal_size); + + /* Add rbsp stop bit and trailing at the end */ + *(p + nal_size - 1) = 0x80; + + return nal_size; +} diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index c98270c2532a..84e0829afc85 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -227,3 +227,5 @@ struct coda_ctx { int display_idx; struct dentry *debugfs_entry; }; + +int coda_h264_padding(int size, char *p); -- GitLab From 79924ca9cf95544213d320e3f20d0aff3288e0cb Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Jul 2014 12:28:45 -0300 Subject: [PATCH 0540/5088] [media] coda: move BIT specific functions into separate file This patch moves the BIT processor specific coda_context_ops, the firmware upload and other related functions from coda-common.c into coda-bit.c. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/Makefile | 2 +- drivers/media/platform/coda/coda-bit.c | 1810 ++++++++++++++++++++ drivers/media/platform/coda/coda-common.c | 1857 +-------------------- drivers/media/platform/coda/coda.h | 56 + 4 files changed, 1893 insertions(+), 1832 deletions(-) create mode 100644 drivers/media/platform/coda/coda-bit.c diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 0e59fbd06ae6..3543291e6273 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,3 +1,3 @@ -coda-objs := coda-common.o coda-h264.o +coda-objs := coda-common.o coda-bit.o coda-h264.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 new file mode 100644 index 000000000000..1d2716d564a1 --- /dev/null +++ b/drivers/media/platform/coda/coda-bit.c @@ -0,0 +1,1810 @@ +/* + * Coda multi-standard codec IP - BIT processor functions + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + * Copyright (C) 2012-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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "coda.h" + +#define CODA7_PS_BUF_SIZE 0x28000 +#define CODA9_PS_SAVE_SIZE (512 * 1024) + +#define CODA_DEFAULT_GAMMA 4096 +#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ + +static inline int coda_is_initialized(struct coda_dev *dev) +{ + return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0); +} + +static inline unsigned long coda_isbusy(struct coda_dev *dev) +{ + return coda_read(dev, CODA_REG_BIT_BUSY); +} + +static int coda_wait_timeout(struct coda_dev *dev) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + while (coda_isbusy(dev)) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + } + return 0; +} + +static void coda_command_async(struct coda_ctx *ctx, int cmd) +{ + struct coda_dev *dev = ctx->dev; + + if (dev->devtype->product == CODA_960 || + dev->devtype->product == CODA_7541) { + /* Restore context related registers to CODA */ + coda_write(dev, ctx->bit_stream_param, + CODA_REG_BIT_BIT_STREAM_PARAM); + coda_write(dev, ctx->frm_dis_flg, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + coda_write(dev, ctx->frame_mem_ctrl, + CODA_REG_BIT_FRAME_MEM_CTRL); + coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); + } + + if (dev->devtype->product == CODA_960) { + coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); + coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); + } + + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + + coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); + coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); + coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); + + coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); +} + +static int coda_command_sync(struct coda_ctx *ctx, int cmd) +{ + struct coda_dev *dev = ctx->dev; + + coda_command_async(ctx, cmd); + return coda_wait_timeout(dev); +} + +int coda_hw_reset(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + unsigned long timeout; + unsigned int idx; + int ret; + + if (!dev->rstc) + return -ENOENT; + + idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); + + if (dev->devtype->product == CODA_960) { + timeout = jiffies + msecs_to_jiffies(100); + coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); + while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { + if (time_after(jiffies, timeout)) + return -ETIME; + cpu_relax(); + } + } + + ret = reset_control_reset(dev->rstc); + if (ret < 0) + return ret; + + if (dev->devtype->product == CODA_960) + coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); + ret = coda_wait_timeout(dev); + coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); + + return ret; +} + +static void coda_kfifo_sync_from_device(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 rd_ptr; + + rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + kfifo->out = (kfifo->in & ~kfifo->mask) | + (rd_ptr - ctx->bitstream.paddr); + if (kfifo->out > kfifo->in) + kfifo->out -= kfifo->mask + 1; +} + +static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 rd_ptr, wr_ptr; + + rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); + coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); + coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); +} + +static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) +{ + struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; + struct coda_dev *dev = ctx->dev; + u32 wr_ptr; + + wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); + coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); +} + +static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf) +{ + u32 src_size = vb2_get_plane_payload(src_buf, 0); + u32 n; + + n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size); + if (n < src_size) + return -ENOSPC; + + dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr, + ctx->bitstream.size, DMA_TO_DEVICE); + + src_buf->v4l2_buf.sequence = ctx->qsequence++; + + return 0; +} + +static bool coda_bitstream_try_queue(struct coda_ctx *ctx, + struct vb2_buffer *src_buf) +{ + int ret; + + if (coda_get_bitstream_payload(ctx) + + vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size) + return false; + + if (vb2_plane_vaddr(src_buf, 0) == NULL) { + v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); + return true; + } + + ret = coda_bitstream_queue(ctx, src_buf); + if (ret < 0) { + v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); + return false; + } + /* Sync read pointer to device */ + if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) + coda_kfifo_sync_to_device_write(ctx); + + ctx->hold = false; + + return true; +} + +void coda_fill_bitstream(struct coda_ctx *ctx) +{ + struct vb2_buffer *src_buf; + struct coda_timestamp *ts; + + while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + + if (coda_bitstream_try_queue(ctx, src_buf)) { + /* + * Source buffer is queued in the bitstream ringbuffer; + * queue the timestamp and mark source buffer as done + */ + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + + ts = kmalloc(sizeof(*ts), GFP_KERNEL); + if (ts) { + ts->sequence = src_buf->v4l2_buf.sequence; + ts->timecode = src_buf->v4l2_buf.timecode; + ts->timestamp = src_buf->v4l2_buf.timestamp; + list_add_tail(&ts->list, &ctx->timestamp_list); + } + + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } else { + break; + } + } +} + +void coda_bit_stream_end_flag(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + + if ((dev->devtype->product == CODA_960) && + coda_isbusy(dev) && + (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { + /* If this context is currently running, update the hardware flag */ + coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + } +} + +static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) +{ + struct coda_dev *dev = ctx->dev; + u32 *p = ctx->parabuf.vaddr; + + if (dev->devtype->product == CODA_DX6) + p[index] = value; + else + p[index ^ 1] = value; +} + +static void coda_free_framebuffers(struct coda_ctx *ctx) +{ + int i; + + for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) + coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]); +} + +static int coda_alloc_framebuffers(struct coda_ctx *ctx, + struct coda_q_data *q_data, u32 fourcc) +{ + struct coda_dev *dev = ctx->dev; + int width, height; + dma_addr_t paddr; + int ysize; + int ret; + int i; + + if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || + ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) { + width = round_up(q_data->width, 16); + height = round_up(q_data->height, 16); + } else { + width = round_up(q_data->width, 8); + height = q_data->height; + } + ysize = width * height; + + /* Allocate frame buffers */ + for (i = 0; i < ctx->num_internal_frames; i++) { + size_t size; + char *name; + + size = ysize + ysize / 2; + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && + dev->devtype->product != CODA_DX6) + size += ysize / 4; + name = kasprintf(GFP_KERNEL, "fb%d", i); + ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], + size, name); + kfree(name); + if (ret < 0) { + coda_free_framebuffers(ctx); + return ret; + } + } + + /* Register frame buffers in the parameter buffer */ + for (i = 0; i < ctx->num_internal_frames; i++) { + paddr = ctx->internal_frames[i].paddr; + coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */ + coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */ + coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */ + + /* mvcol buffer for h.264 */ + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && + dev->devtype->product != CODA_DX6) + coda_parabuf_write(ctx, 96 + i, + ctx->internal_frames[i].paddr + + ysize + ysize/4 + ysize/4); + } + + /* 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 + + ysize + ysize/4 + ysize/4); + + return 0; +} + +static void coda_free_context_buffers(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + + coda_free_aux_buf(dev, &ctx->slicebuf); + coda_free_aux_buf(dev, &ctx->psbuf); + if (dev->devtype->product != CODA_DX6) + coda_free_aux_buf(dev, &ctx->workbuf); +} + +static int coda_alloc_context_buffers(struct coda_ctx *ctx, + struct coda_q_data *q_data) +{ + struct coda_dev *dev = ctx->dev; + size_t size; + int ret; + + if (dev->devtype->product == CODA_DX6) + return 0; + + if (ctx->psbuf.vaddr) { + v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n"); + return -EBUSY; + } + if (ctx->slicebuf.vaddr) { + v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n"); + return -EBUSY; + } + if (ctx->workbuf.vaddr) { + v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n"); + ret = -EBUSY; + return -ENOMEM; + } + + if (q_data->fourcc == V4L2_PIX_FMT_H264) { + /* worst case slice size */ + size = (DIV_ROUND_UP(q_data->width, 16) * + DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; + ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer", + ctx->slicebuf.size); + return ret; + } + } + + if (dev->devtype->product == CODA_7541) { + ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer"); + goto err; + } + } + + size = dev->devtype->workbuf_size; + if (dev->devtype->product == CODA_960 && + q_data->fourcc == V4L2_PIX_FMT_H264) + size += CODA9_PS_SAVE_SIZE; + ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf"); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer", + ctx->workbuf.size); + goto err; + } + + return 0; + +err: + coda_free_context_buffers(ctx); + return ret; +} + +static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf, + int header_code, u8 *header, int *size) +{ + struct coda_dev *dev = ctx->dev; + size_t bufsize; + int ret; + int i; + + if (dev->devtype->product == CODA_960) + memset(vb2_plane_vaddr(buf, 0), 0, 64); + + coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), + CODA_CMD_ENC_HEADER_BB_START); + bufsize = vb2_plane_size(buf, 0); + if (dev->devtype->product == CODA_960) + bufsize /= 1024; + coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); + coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); + ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); + return ret; + } + + if (dev->devtype->product == CODA_960) { + for (i = 63; i > 0; i--) + if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0) + break; + *size = i + 1; + } else { + *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - + coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); + } + memcpy(header, vb2_plane_vaddr(buf, 0), *size); + + return 0; +} + +static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) +{ + phys_addr_t ret; + + size = round_up(size, 1024); + if (size > iram->remaining) + return 0; + iram->remaining -= size; + + ret = iram->next_paddr; + iram->next_paddr += size; + + return ret; +} + +static void coda_setup_iram(struct coda_ctx *ctx) +{ + struct coda_iram_info *iram_info = &ctx->iram_info; + struct coda_dev *dev = ctx->dev; + int mb_width; + int dbk_bits; + int bit_bits; + int ip_bits; + + memset(iram_info, 0, sizeof(*iram_info)); + iram_info->next_paddr = dev->iram.paddr; + iram_info->remaining = dev->iram.size; + + switch (dev->devtype->product) { + case CODA_7541: + dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; + bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; + ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + break; + case CODA_960: + dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; + bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; + ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + break; + default: /* CODA_DX6 */ + return; + } + + if (ctx->inst_type == CODA_INST_ENCODER) { + struct coda_q_data *q_data_src; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + mb_width = DIV_ROUND_UP(q_data_src->width, 16); + + /* Prioritize in case IRAM is too small for everything */ + if (dev->devtype->product == CODA_7541) { + iram_info->search_ram_size = round_up(mb_width * 16 * + 36 + 2048, 1024); + iram_info->search_ram_paddr = coda_iram_alloc(iram_info, + iram_info->search_ram_size); + if (!iram_info->search_ram_paddr) { + pr_err("IRAM is smaller than the search ram size\n"); + goto out; + } + iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE | + CODA7_USE_ME_ENABLE; + } + + /* Only H.264BP and H.263P3 are considered */ + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width); + if (!iram_info->buf_dbk_c_use) + goto out; + iram_info->axi_sram_use |= dbk_bits; + + iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_bit_use) + goto out; + iram_info->axi_sram_use |= bit_bits; + + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_ip_ac_dc_use) + goto out; + iram_info->axi_sram_use |= ip_bits; + + /* OVL and BTP disabled for encoder */ + } else if (ctx->inst_type == CODA_INST_DECODER) { + struct coda_q_data *q_data_dst; + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + mb_width = DIV_ROUND_UP(q_data_dst->width, 16); + + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_dbk_c_use) + goto out; + iram_info->axi_sram_use |= dbk_bits; + + iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_bit_use) + goto out; + iram_info->axi_sram_use |= bit_bits; + + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); + if (!iram_info->buf_ip_ac_dc_use) + goto out; + iram_info->axi_sram_use |= ip_bits; + + /* OVL and BTP unused as there is no VC1 support yet */ + } + +out: + if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "IRAM smaller than needed\n"); + + if (dev->devtype->product == CODA_7541) { + /* TODO - Enabling these causes picture errors on CODA7541 */ + if (ctx->inst_type == CODA_INST_DECODER) { + /* fw 1.4.50 */ + iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | + CODA7_USE_IP_ENABLE); + } else { + /* fw 13.4.29 */ + iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | + CODA7_USE_HOST_DBK_ENABLE | + CODA7_USE_IP_ENABLE | + CODA7_USE_DBK_ENABLE); + } + } +} + +static u32 coda_supported_firmwares[] = { + CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), + CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), + CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), +}; + +static bool coda_firmware_supported(u32 vernum) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) + if (vernum == coda_supported_firmwares[i]) + return true; + return false; +} + +int coda_check_firmware(struct coda_dev *dev) +{ + u16 product, major, minor, release; + u32 data; + int ret; + + ret = clk_prepare_enable(dev->clk_per); + if (ret) + goto err_clk_per; + + ret = clk_prepare_enable(dev->clk_ahb); + if (ret) + goto err_clk_ahb; + + coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); + coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); + coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); + if (coda_wait_timeout(dev)) { + v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); + ret = -EIO; + goto err_run_cmd; + } + + if (dev->devtype->product == CODA_960) { + data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); + v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", + data); + } + + /* Check we are compatible with the loaded firmware */ + data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); + product = CODA_FIRMWARE_PRODUCT(data); + major = CODA_FIRMWARE_MAJOR(data); + minor = CODA_FIRMWARE_MINOR(data); + release = CODA_FIRMWARE_RELEASE(data); + + clk_disable_unprepare(dev->clk_per); + clk_disable_unprepare(dev->clk_ahb); + + if (product != dev->devtype->product) { + v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s," + " Version: %u.%u.%u\n", + coda_product_name(dev->devtype->product), + coda_product_name(product), major, minor, release); + return -EINVAL; + } + + v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", + coda_product_name(product)); + + if (coda_firmware_supported(data)) { + v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", + major, minor, release); + } else { + v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: " + "%u.%u.%u\n", major, minor, release); + } + + return 0; + +err_run_cmd: + clk_disable_unprepare(dev->clk_ahb); +err_clk_ahb: + clk_disable_unprepare(dev->clk_per); +err_clk_per: + return ret; +} + +/* + * Encoder context operations + */ + +static int coda_start_encoding(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + struct coda_q_data *q_data_src, *q_data_dst; + u32 bitstream_buf, bitstream_size; + struct vb2_buffer *buf; + int gamma, ret, value; + u32 dst_fourcc; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fourcc; + + /* Allocate per-instance buffers */ + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + + buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); + bitstream_size = q_data_dst->sizeimage; + + if (!coda_is_initialized(dev)) { + v4l2_err(v4l2_dev, "coda is not initialized.\n"); + return -EFAULT; + } + + mutex_lock(&dev->coda_mutex); + + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); + coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); + switch (dev->devtype->product) { + case CODA_DX6: + coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | + CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); + break; + case CODA_960: + coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); + /* fallthrough */ + case CODA_7541: + coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | + CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); + break; + } + + value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL); + value &= ~(1 << 2 | 0x7 << 9); + ctx->frame_mem_ctrl = value; + coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL); + + if (dev->devtype->product == CODA_DX6) { + /* Configure the coda */ + coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); + } + + /* Could set rotation here if needed */ + switch (dev->devtype->product) { + case CODA_DX6: + value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET; + value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + break; + case CODA_7541: + if (dst_fourcc == V4L2_PIX_FMT_H264) { + value = (round_up(q_data_src->width, 16) & + CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; + value |= (round_up(q_data_src->height, 16) & + CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + break; + } + /* fallthrough */ + case CODA_960: + value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; + value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); + coda_write(dev, ctx->params.framerate, + CODA_CMD_ENC_SEQ_SRC_F_RATE); + + ctx->params.codec_mode = ctx->codec->mode; + switch (dst_fourcc) { + case V4L2_PIX_FMT_MPEG4: + if (dev->devtype->product == CODA_960) + coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + else + coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); + break; + case V4L2_PIX_FMT_H264: + if (dev->devtype->product == CODA_960) + coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + else + coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + if (ctx->params.h264_deblk_enabled) { + value = ((ctx->params.h264_deblk_alpha & + CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << + CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | + ((ctx->params.h264_deblk_beta & + CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << + CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET); + } else { + value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); + break; + default: + v4l2_err(v4l2_dev, + "dst format (0x%08x) invalid.\n", dst_fourcc); + ret = -EINVAL; + goto out; + } + + switch (ctx->params.slice_mode) { + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: + value = 0; + break; + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: + value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; + value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + value |= 1 & CODA_SLICING_MODE_MASK; + break; + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: + value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; + value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + value |= 1 & CODA_SLICING_MODE_MASK; + break; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); + value = ctx->params.gop_size & CODA_GOP_SIZE_MASK; + coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); + + if (ctx->params.bitrate) { + /* Rate control enabled */ + value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; + value |= 1 & CODA_RATECONTROL_ENABLE_MASK; + if (dev->devtype->product == CODA_960) + value |= BIT(31); /* disable autoskip */ + } else { + value = 0; + } + 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.intra_refresh, + CODA_CMD_ENC_SEQ_INTRA_REFRESH); + + coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); + coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); + + + value = 0; + if (dev->devtype->product == CODA_960) + gamma = CODA9_DEFAULT_GAMMA; + else + gamma = CODA_DEFAULT_GAMMA; + if (gamma > 0) { + coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, + CODA_CMD_ENC_SEQ_RC_GAMMA); + } + + if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { + coda_write(dev, + ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | + ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, + CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); + } + if (dev->devtype->product == CODA_960) { + if (ctx->params.h264_max_qp) + value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; + if (CODA_DEFAULT_GAMMA > 0) + value |= 1 << CODA9_OPTION_GAMMA_OFFSET; + } else { + if (CODA_DEFAULT_GAMMA > 0) { + if (dev->devtype->product == CODA_DX6) + value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; + else + value |= 1 << CODA7_OPTION_GAMMA_OFFSET; + } + if (ctx->params.h264_min_qp) + value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; + if (ctx->params.h264_max_qp) + value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); + + coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); + + coda_setup_iram(ctx); + + if (dst_fourcc == V4L2_PIX_FMT_H264) { + switch (dev->devtype->product) { + case CODA_DX6: + value = FMO_SLICE_SAVE_BUF_SIZE << 7; + coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); + break; + case CODA_7541: + coda_write(dev, ctx->iram_info.search_ram_paddr, + CODA7_CMD_ENC_SEQ_SEARCH_BASE); + coda_write(dev, ctx->iram_info.search_ram_size, + CODA7_CMD_ENC_SEQ_SEARCH_SIZE); + break; + case CODA_960: + coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); + coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); + } + } + + ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); + if (ret < 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); + goto out; + } + + if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); + ret = -EFAULT; + goto out; + } + + if (dev->devtype->product == CODA_960) + ctx->num_internal_frames = 4; + else + ctx->num_internal_frames = 2; + ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); + if (ret < 0) { + v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); + goto out; + } + + coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, q_data_src->bytesperline, + CODA_CMD_SET_FRAME_BUF_STRIDE); + if (dev->devtype->product == CODA_7541) { + coda_write(dev, q_data_src->bytesperline, + CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); + } + if (dev->devtype->product != CODA_DX6) { + coda_write(dev, ctx->iram_info.buf_bit_use, + CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); + coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, + CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_y_use, + CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_c_use, + 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) { + coda_write(dev, ctx->iram_info.buf_btp_use, + CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); + + /* FIXME */ + coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); + coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B); + } + } + + ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); + if (ret < 0) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); + goto out; + } + + /* Save stream headers */ + buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + /* + * Get SPS in the first frame and copy it to an + * intermediate buffer. + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, + &ctx->vpu_header[0][0], + &ctx->vpu_header_size[0]); + if (ret < 0) + goto out; + + /* + * Get PPS in the first frame and copy it to an + * intermediate buffer. + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, + &ctx->vpu_header[1][0], + &ctx->vpu_header_size[1]); + if (ret < 0) + goto out; + + /* + * Length of H.264 headers is variable and thus it might not be + * aligned for the coda to append the encoded frame. In that is + * the case a filler NAL must be added to header 2. + */ + ctx->vpu_header_size[2] = coda_h264_padding( + (ctx->vpu_header_size[0] + + ctx->vpu_header_size[1]), + ctx->vpu_header[2]); + break; + case V4L2_PIX_FMT_MPEG4: + /* + * Get VOS in the first frame and copy it to an + * intermediate buffer + */ + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, + &ctx->vpu_header[0][0], + &ctx->vpu_header_size[0]); + if (ret < 0) + goto out; + + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, + &ctx->vpu_header[1][0], + &ctx->vpu_header_size[1]); + if (ret < 0) + goto out; + + ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, + &ctx->vpu_header[2][0], + &ctx->vpu_header_size[2]); + if (ret < 0) + goto out; + break; + default: + /* No more formats need to save headers at the moment */ + break; + } + +out: + mutex_unlock(&dev->coda_mutex); + return ret; +} + +static int coda_prepare_encode(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + struct vb2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + int force_ipicture; + int quant_param = 0; + u32 picture_y, picture_cb, picture_cr; + u32 pic_stream_buffer_addr, pic_stream_buffer_size; + u32 dst_fourcc; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fourcc; + + src_buf->v4l2_buf.sequence = ctx->osequence; + dst_buf->v4l2_buf.sequence = ctx->osequence; + ctx->osequence++; + + /* + * Workaround coda firmware BUG that only marks the first + * frame as IDR. This is a problem for some decoders that can't + * recover when a frame is lost. + */ + if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) { + src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; + src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; + } else { + src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; + } + + if (dev->devtype->product == CODA_960) + coda_set_gdi_regs(ctx); + + /* + * Copy headers at the beginning of the first frame for H.264 only. + * In MPEG4 they are already copied by the coda. + */ + if (src_buf->v4l2_buf.sequence == 0) { + pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(dst_buf, 0) + + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1] + + ctx->vpu_header_size[2]; + pic_stream_buffer_size = CODA_MAX_FRAME_SIZE - + ctx->vpu_header_size[0] - + ctx->vpu_header_size[1] - + ctx->vpu_header_size[2]; + memcpy(vb2_plane_vaddr(dst_buf, 0), + &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); + memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0], + &ctx->vpu_header[1][0], ctx->vpu_header_size[1]); + memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1], &ctx->vpu_header[2][0], + ctx->vpu_header_size[2]); + } else { + pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(dst_buf, 0); + pic_stream_buffer_size = CODA_MAX_FRAME_SIZE; + } + + if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { + force_ipicture = 1; + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + quant_param = ctx->params.h264_intra_qp; + break; + case V4L2_PIX_FMT_MPEG4: + quant_param = ctx->params.mpeg4_intra_qp; + break; + default: + v4l2_warn(&ctx->dev->v4l2_dev, + "cannot set intra qp, fmt not supported\n"); + break; + } + } else { + force_ipicture = 0; + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + quant_param = ctx->params.h264_inter_qp; + break; + case V4L2_PIX_FMT_MPEG4: + quant_param = ctx->params.mpeg4_inter_qp; + break; + default: + v4l2_warn(&ctx->dev->v4l2_dev, + "cannot set inter qp, fmt not supported\n"); + break; + } + } + + /* submit */ + coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); + coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); + + + picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0); + switch (q_data_src->fourcc) { + case V4L2_PIX_FMT_YVU420: + /* Switch Cb and Cr for YVU420 format */ + picture_cr = picture_y + q_data_src->bytesperline * + q_data_src->height; + picture_cb = picture_cr + q_data_src->bytesperline / 2 * + q_data_src->height / 2; + break; + case V4L2_PIX_FMT_YUV420: + default: + picture_cb = picture_y + q_data_src->bytesperline * + q_data_src->height; + picture_cr = picture_cb + q_data_src->bytesperline / 2 * + q_data_src->height / 2; + break; + } + + if (dev->devtype->product == CODA_960) { + coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); + coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE); + coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); + + coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y); + coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB); + coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR); + } else { + coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y); + coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB); + coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR); + } + coda_write(dev, force_ipicture << 1 & 0x2, + CODA_CMD_ENC_PIC_OPTION); + + coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); + coda_write(dev, pic_stream_buffer_size / 1024, + CODA_CMD_ENC_PIC_BB_SIZE); + + if (!ctx->streamon_out) { + /* After streamoff on the output side, set the stream end flag */ + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + } + + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + + return 0; +} + +static void coda_finish_encode(struct coda_ctx *ctx) +{ + struct vb2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + u32 wr_ptr, start_ptr; + + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + /* Get results from the coda */ + start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); + wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); + + /* Calculate bytesused field */ + if (dst_buf->v4l2_buf.sequence == 0) { + vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr + + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1] + + ctx->vpu_header_size[2]); + } else { + vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr); + } + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n", + wr_ptr - start_ptr); + + coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); + coda_read(dev, CODA_RET_ENC_PIC_FLAG); + + if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) { + dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; + } else { + dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; + } + + dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_buf->v4l2_buf.flags |= + src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; + + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + + ctx->gopcounter--; + if (ctx->gopcounter < 0) + ctx->gopcounter = ctx->params.gop_size - 1; + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "job finished: encoding frame (%d) (%s)\n", + dst_buf->v4l2_buf.sequence, + (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? + "KEYFRAME" : "PFRAME"); +} + +static void coda_seq_end_work(struct work_struct *work) +{ + struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); + struct coda_dev *dev = ctx->dev; + + mutex_lock(&ctx->buffer_mutex); + mutex_lock(&dev->coda_mutex); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__); + if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { + v4l2_err(&dev->v4l2_dev, + "CODA_COMMAND_SEQ_END failed\n"); + } + + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + + coda_free_framebuffers(ctx); + coda_free_context_buffers(ctx); + + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); +} + +static void coda_bit_release(struct coda_ctx *ctx) +{ + coda_free_framebuffers(ctx); + coda_free_context_buffers(ctx); +} + +const struct coda_context_ops coda_bit_encode_ops = { + .queue_init = coda_encoder_queue_init, + .start_streaming = coda_start_encoding, + .prepare_run = coda_prepare_encode, + .finish_run = coda_finish_encode, + .seq_end_work = coda_seq_end_work, + .release = coda_bit_release, +}; + +/* + * Decoder context operations + */ + +static int __coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + u32 bitstream_buf, bitstream_size; + struct coda_dev *dev = ctx->dev; + int width, height; + u32 src_fourcc; + u32 val; + int ret; + + /* Start decoding */ + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + bitstream_buf = ctx->bitstream.paddr; + bitstream_size = ctx->bitstream.size; + src_fourcc = q_data_src->fourcc; + + /* Allocate per-instance buffers */ + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + + /* Update coda bitstream read and write pointers from kfifo */ + coda_kfifo_sync_to_device_full(ctx); + + ctx->display_idx = -1; + ctx->frm_dis_flg = 0; + coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + + coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE, + CODA_REG_BIT_BIT_STREAM_PARAM); + + coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); + coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); + val = 0; + if ((dev->devtype->product == CODA_7541) || + (dev->devtype->product == CODA_960)) + val |= CODA_REORDER_ENABLE; + coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); + + ctx->params.codec_mode = ctx->codec->mode; + if (dev->devtype->product == CODA_960 && + src_fourcc == V4L2_PIX_FMT_MPEG4) + ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; + else + ctx->params.codec_mode_aux = 0; + if (src_fourcc == V4L2_PIX_FMT_H264) { + if (dev->devtype->product == CODA_7541) { + coda_write(dev, ctx->psbuf.paddr, + CODA_CMD_DEC_SEQ_PS_BB_START); + coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), + CODA_CMD_DEC_SEQ_PS_BB_SIZE); + } + if (dev->devtype->product == CODA_960) { + coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); + coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); + } + } + if (dev->devtype->product != CODA_960) + coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); + + if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) { + v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); + coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); + return -ETIMEDOUT; + } + + /* Update kfifo out pointer from coda bitstream read pointer */ + coda_kfifo_sync_from_device(ctx); + + coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); + + if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { + v4l2_err(&dev->v4l2_dev, + "CODA_COMMAND_SEQ_INIT failed, error code = %d\n", + coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); + return -EAGAIN; + } + + val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); + if (dev->devtype->product == CODA_DX6) { + width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; + height = val & CODADX6_PICHEIGHT_MASK; + } else { + width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; + height = val & CODA7_PICHEIGHT_MASK; + } + + if (width > q_data_dst->width || height > q_data_dst->height) { + v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", + width, height, q_data_dst->width, q_data_dst->height); + return -EINVAL; + } + + width = round_up(width, 16); + height = round_up(height, 16); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n", + __func__, ctx->idx, width, height); + + ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); + if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { + v4l2_err(&dev->v4l2_dev, + "not enough framebuffers to decode (%d < %d)\n", + CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); + return -EINVAL; + } + + if (src_fourcc == V4L2_PIX_FMT_H264) { + u32 left_right; + u32 top_bottom; + + left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); + top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); + + q_data_dst->rect.left = (left_right >> 10) & 0x3ff; + q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; + q_data_dst->rect.width = width - q_data_dst->rect.left - + (left_right & 0x3ff); + q_data_dst->rect.height = height - q_data_dst->rect.top - + (top_bottom & 0x3ff); + } + + ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); + if (ret < 0) + return ret; + + /* Tell the decoder how many frame buffers we allocated. */ + coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE); + + if (dev->devtype->product != CODA_DX6) { + /* Set secondary AXI IRAM */ + coda_setup_iram(ctx); + + coda_write(dev, ctx->iram_info.buf_bit_use, + CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); + coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, + CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_y_use, + CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); + coda_write(dev, ctx->iram_info.buf_dbk_c_use, + 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) + coda_write(dev, ctx->iram_info.buf_btp_use, + CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); + } + + if (dev->devtype->product == CODA_960) { + coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); + + coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE); + coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET | + 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET, + CODA9_CMD_SET_FRAME_CACHE_CONFIG); + } + + if (src_fourcc == V4L2_PIX_FMT_H264) { + coda_write(dev, ctx->slicebuf.paddr, + CODA_CMD_SET_FRAME_SLICE_BB_START); + coda_write(dev, ctx->slicebuf.size / 1024, + CODA_CMD_SET_FRAME_SLICE_BB_SIZE); + } + + if (dev->devtype->product == CODA_7541) { + int max_mb_x = 1920 / 16; + int max_mb_y = 1088 / 16; + int max_mb_num = max_mb_x * max_mb_y; + + coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, + CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); + } else if (dev->devtype->product == CODA_960) { + int max_mb_x = 1920 / 16; + int max_mb_y = 1088 / 16; + int max_mb_num = max_mb_x * max_mb_y; + + coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, + CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); + } + + if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { + v4l2_err(&ctx->dev->v4l2_dev, + "CODA_COMMAND_SET_FRAME_BUF timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + int ret; + + mutex_lock(&dev->coda_mutex); + ret = __coda_start_decoding(ctx); + mutex_unlock(&dev->coda_mutex); + + return ret; +} + +static int coda_prepare_decode(struct coda_ctx *ctx) +{ + struct vb2_buffer *dst_buf; + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_dst; + u32 stridey, height; + u32 picture_y, picture_cb, picture_cr; + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + if (ctx->params.rot_mode & CODA_ROT_90) { + stridey = q_data_dst->height; + height = q_data_dst->width; + } else { + stridey = q_data_dst->width; + height = q_data_dst->height; + } + + /* Try to copy source buffer contents into the bitstream ringbuffer */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx); + mutex_unlock(&ctx->bitstream_mutex); + + if (coda_get_bitstream_payload(ctx) < 512 && + (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "bitstream payload: %d, skipping\n", + coda_get_bitstream_payload(ctx)); + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + return -EAGAIN; + } + + /* Run coda_start_decoding (again) if not yet initialized */ + if (!ctx->initialized) { + int ret = __coda_start_decoding(ctx); + + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + return -EAGAIN; + } else { + ctx->initialized = 1; + } + } + + if (dev->devtype->product == CODA_960) + coda_set_gdi_regs(ctx); + + /* Set rotator output */ + picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) { + /* Switch Cr and Cb for YVU420 format */ + picture_cr = picture_y + stridey * height; + picture_cb = picture_cr + stridey / 2 * height / 2; + } else { + picture_cb = picture_y + stridey * height; + picture_cr = picture_cb + stridey / 2 * height / 2; + } + + if (dev->devtype->product == CODA_960) { + /* + * The CODA960 seems to have an internal list of buffers with + * 64 entries that includes the registered frame buffers as + * well as the rotator buffer output. + * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames. + */ + coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index, + CODA9_CMD_DEC_PIC_ROT_INDEX); + coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y); + coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB); + coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR); + coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE); + } else { + coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y); + coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB); + coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR); + coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE); + } + coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, + CODA_CMD_DEC_PIC_ROT_MODE); + + switch (dev->devtype->product) { + case CODA_DX6: + /* TBD */ + case CODA_7541: + coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); + break; + case CODA_960: + coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */ + break; + } + + coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); + + coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); + coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); + + if (dev->devtype->product != CODA_DX6) + coda_write(dev, ctx->iram_info.axi_sram_use, + CODA7_REG_BIT_AXI_SRAM_USE); + + coda_kfifo_sync_to_device_full(ctx); + + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); + + return 0; +} + +static void coda_finish_decode(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_src; + struct coda_q_data *q_data_dst; + struct vb2_buffer *dst_buf; + struct coda_timestamp *ts; + int width, height; + int decoded_idx; + int display_idx; + u32 src_fourcc; + int success; + u32 err_mb; + u32 val; + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + /* Update kfifo out pointer from coda bitstream read pointer */ + coda_kfifo_sync_from_device(ctx); + + /* + * in stream-end mode, the read pointer can overshoot the write pointer + * by up to 512 bytes + */ + if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { + if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512) + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + } + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + src_fourcc = q_data_src->fourcc; + + val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); + if (val != 1) + pr_err("DEC_PIC_SUCCESS = %d\n", val); + + success = val & 0x1; + if (!success) + v4l2_err(&dev->v4l2_dev, "decode failed\n"); + + if (src_fourcc == V4L2_PIX_FMT_H264) { + if (val & (1 << 3)) + v4l2_err(&dev->v4l2_dev, + "insufficient PS buffer space (%d bytes)\n", + ctx->psbuf.size); + if (val & (1 << 2)) + v4l2_err(&dev->v4l2_dev, + "insufficient slice buffer space (%d bytes)\n", + ctx->slicebuf.size); + } + + val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); + width = (val >> 16) & 0xffff; + height = val & 0xffff; + + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + /* frame crop information */ + if (src_fourcc == V4L2_PIX_FMT_H264) { + u32 left_right; + u32 top_bottom; + + left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); + top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); + + if (left_right == 0xffffffff && top_bottom == 0xffffffff) { + /* Keep current crop information */ + } else { + struct v4l2_rect *rect = &q_data_dst->rect; + + rect->left = left_right >> 16 & 0xffff; + rect->top = top_bottom >> 16 & 0xffff; + rect->width = width - rect->left - + (left_right & 0xffff); + rect->height = height - rect->top - + (top_bottom & 0xffff); + } + } else { + /* no cropping */ + } + + err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); + if (err_mb > 0) + v4l2_err(&dev->v4l2_dev, + "errors in %d macroblocks\n", err_mb); + + if (dev->devtype->product == CODA_7541) { + val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); + if (val == 0) { + /* not enough bitstream data */ + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "prescan failed: %d\n", val); + ctx->hold = true; + return; + } + } + + ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + + /* + * The previous display frame was copied out by the rotator, + * now it can be overwritten again + */ + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) { + ctx->frm_dis_flg &= ~(1 << ctx->display_idx); + coda_write(dev, ctx->frm_dis_flg, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + } + + /* + * The index of the last decoded frame, not necessarily in + * display order, and the index of the next display frame. + * The latter could have been decoded in a previous run. + */ + decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); + display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); + + if (decoded_idx == -1) { + /* no frame was decoded, but we might have a display frame */ + if (display_idx >= 0 && display_idx < ctx->num_internal_frames) + ctx->sequence_offset++; + else if (ctx->display_idx < 0) + ctx->hold = true; + } else if (decoded_idx == -2) { + /* no frame was decoded, we still return the remaining buffers */ + } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { + v4l2_err(&dev->v4l2_dev, + "decoded frame index out of range: %d\n", decoded_idx); + } else { + ts = list_first_entry(&ctx->timestamp_list, + struct coda_timestamp, list); + list_del(&ts->list); + val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; + val -= ctx->sequence_offset; + if (val != (ts->sequence & 0xffff)) { + v4l2_err(&dev->v4l2_dev, + "sequence number mismatch (%d(%d) != %d)\n", + val, ctx->sequence_offset, ts->sequence); + } + ctx->frame_timestamps[decoded_idx] = *ts; + kfree(ts); + + val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; + if (val == 0) + ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; + else if (val == 1) + ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME; + else + ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME; + + ctx->frame_errors[decoded_idx] = err_mb; + } + + if (display_idx == -1) { + /* + * no more frames to be decoded, but there could still + * be rotator output to dequeue + */ + ctx->hold = true; + } else if (display_idx == -3) { + /* possibly prescan failure */ + } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { + v4l2_err(&dev->v4l2_dev, + "presentation frame index out of range: %d\n", + display_idx); + } + + /* If a frame was copied out, return it */ + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) { + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + dst_buf->v4l2_buf.sequence = ctx->osequence++; + + dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | + V4L2_BUF_FLAG_PFRAME | + V4L2_BUF_FLAG_BFRAME); + dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx]; + ts = &ctx->frame_timestamps[ctx->display_idx]; + dst_buf->v4l2_buf.timecode = ts->timecode; + dst_buf->v4l2_buf.timestamp = ts->timestamp; + + vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2); + + v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "job finished: decoding frame (%d) (%s)\n", + dst_buf->v4l2_buf.sequence, + (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? + "KEYFRAME" : "PFRAME"); + } else { + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "job finished: no frame decoded\n"); + } + + /* The rotator will copy the current display frame next time */ + ctx->display_idx = display_idx; +} + +const struct coda_context_ops coda_bit_decode_ops = { + .queue_init = coda_decoder_queue_init, + .start_streaming = coda_start_decoding, + .prepare_run = coda_prepare_decode, + .finish_run = coda_finish_decode, + .seq_end_work = coda_seq_end_work, + .release = coda_bit_release, +}; + +irqreturn_t coda_irq_handler(int irq, void *data) +{ + struct coda_dev *dev = data; + struct coda_ctx *ctx; + + /* read status register to attend the IRQ */ + coda_read(dev, CODA_REG_BIT_INT_STATUS); + coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, + CODA_REG_BIT_INT_CLEAR); + + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (ctx == NULL) { + v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); + mutex_unlock(&dev->coda_mutex); + return IRQ_HANDLED; + } + + if (ctx->aborting) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "task has been aborted\n"); + } + + if (coda_isbusy(ctx->dev)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "coda is still busy!!!!\n"); + return IRQ_NONE; + } + + complete(&ctx->completion); + + return IRQ_HANDLED; +} diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 574742e1e82c..dc9740d0ea5e 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -48,12 +48,6 @@ #define CODA_PARA_BUF_SIZE (10 * 1024) #define CODA_ISRAM_SIZE (2048 * 2) -#define CODA7_PS_BUF_SIZE 0x28000 -#define CODA9_PS_SAVE_SIZE (512 * 1024) - -#define CODA_DEFAULT_GAMMA 4096 -#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ - #define MIN_W 176 #define MIN_H 144 @@ -63,7 +57,7 @@ #define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh) -static int coda_debug; +int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-1)"); @@ -88,128 +82,6 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg) return data; } -static inline unsigned long coda_isbusy(struct coda_dev *dev) -{ - return coda_read(dev, CODA_REG_BIT_BUSY); -} - -static inline int coda_is_initialized(struct coda_dev *dev) -{ - return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0); -} - -static int coda_wait_timeout(struct coda_dev *dev) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - - while (coda_isbusy(dev)) { - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - } - return 0; -} - -static void coda_command_async(struct coda_ctx *ctx, int cmd) -{ - struct coda_dev *dev = ctx->dev; - - if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541) { - /* Restore context related registers to CODA */ - coda_write(dev, ctx->bit_stream_param, - CODA_REG_BIT_BIT_STREAM_PARAM); - coda_write(dev, ctx->frm_dis_flg, - CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - coda_write(dev, ctx->frame_mem_ctrl, - CODA_REG_BIT_FRAME_MEM_CTRL); - coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); - } - - if (dev->devtype->product == CODA_960) { - coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); - coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); - } - - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - - coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); - coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); - coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); - - coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); -} - -static int coda_command_sync(struct coda_ctx *ctx, int cmd) -{ - struct coda_dev *dev = ctx->dev; - - coda_command_async(ctx, cmd); - return coda_wait_timeout(dev); -} - -static int coda_hw_reset(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - unsigned long timeout; - unsigned int idx; - int ret; - - if (!dev->rstc) - return -ENOENT; - - idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); - - if (dev->devtype->product == CODA_960) { - timeout = jiffies + msecs_to_jiffies(100); - coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); - while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { - if (time_after(jiffies, timeout)) - return -ETIME; - cpu_relax(); - } - } - - ret = reset_control_reset(dev->rstc); - if (ret < 0) - return ret; - - if (dev->devtype->product == CODA_960) - coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); - ret = coda_wait_timeout(dev); - coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); - - return ret; -} - -static void coda_bit_stream_end_flag(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - - if ((dev->devtype->product == CODA_960) && - coda_isbusy(dev) && - (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - /* If this context is currently running, update the hardware flag */ - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } -} - -static struct coda_q_data *get_q_data(struct coda_ctx *ctx, - enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return &(ctx->q_data[V4L2_M2M_SRC]); - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &(ctx->q_data[V4L2_M2M_DST]); - default: - return NULL; - } -} - /* * Array of all formats supported by any version of Coda: */ @@ -330,7 +202,7 @@ static void coda_get_max_dimensions(struct coda_dev *dev, *max_h = h; } -static char *coda_product_name(int product) +const char *coda_product_name(int product) { static char buf[9]; @@ -802,124 +674,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static int __coda_start_decoding(struct coda_ctx *ctx); - -static inline int coda_get_bitstream_payload(struct coda_ctx *ctx) -{ - return kfifo_len(&ctx->bitstream_fifo); -} - -static void coda_kfifo_sync_from_device(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 rd_ptr; - - rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - kfifo->out = (kfifo->in & ~kfifo->mask) | - (rd_ptr - ctx->bitstream.paddr); - if (kfifo->out > kfifo->in) - kfifo->out -= kfifo->mask + 1; -} - -static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 rd_ptr, wr_ptr; - - rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); - coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); - coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); -} - -static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) -{ - struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; - struct coda_dev *dev = ctx->dev; - u32 wr_ptr; - - wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); - coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); -} - -static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf) -{ - u32 src_size = vb2_get_plane_payload(src_buf, 0); - u32 n; - - n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size); - if (n < src_size) - return -ENOSPC; - - dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr, - ctx->bitstream.size, DMA_TO_DEVICE); - - src_buf->v4l2_buf.sequence = ctx->qsequence++; - - return 0; -} - -static bool coda_bitstream_try_queue(struct coda_ctx *ctx, - struct vb2_buffer *src_buf) -{ - int ret; - - if (coda_get_bitstream_payload(ctx) + - vb2_get_plane_payload(src_buf, 0) + 512 >= ctx->bitstream.size) - return false; - - if (vb2_plane_vaddr(src_buf, 0) == NULL) { - v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); - return true; - } - - ret = coda_bitstream_queue(ctx, src_buf); - if (ret < 0) { - v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); - return false; - } - /* Sync read pointer to device */ - if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) - coda_kfifo_sync_to_device_write(ctx); - - ctx->hold = false; - - return true; -} - -static void coda_fill_bitstream(struct coda_ctx *ctx) -{ - struct vb2_buffer *src_buf; - struct coda_timestamp *ts; - - while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - - if (coda_bitstream_try_queue(ctx, src_buf)) { - /* - * Source buffer is queued in the bitstream ringbuffer; - * queue the timestamp and mark source buffer as done - */ - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - - ts = kmalloc(sizeof(*ts), GFP_KERNEL); - if (ts) { - ts->sequence = src_buf->v4l2_buf.sequence; - ts->timecode = src_buf->v4l2_buf.timecode; - ts->timestamp = src_buf->v4l2_buf.timestamp; - list_add_tail(&ts->list, &ctx->timestamp_list); - } - - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - } else { - break; - } - } -} - -static void coda_set_gdi_regs(struct coda_ctx *ctx) +void coda_set_gdi_regs(struct coda_ctx *ctx) { struct gdi_tiled_map *tiled_map = &ctx->tiled_map; struct coda_dev *dev = ctx->dev; @@ -943,264 +698,6 @@ static void coda_set_gdi_regs(struct coda_ctx *ctx) /* * Mem-to-mem operations. */ -static int coda_prepare_decode(struct coda_ctx *ctx) -{ - struct vb2_buffer *dst_buf; - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data_dst; - u32 stridey, height; - u32 picture_y, picture_cb, picture_cr; - - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - if (ctx->params.rot_mode & CODA_ROT_90) { - stridey = q_data_dst->height; - height = q_data_dst->width; - } else { - stridey = q_data_dst->width; - height = q_data_dst->height; - } - - /* Try to copy source buffer contents into the bitstream ringbuffer */ - mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx); - mutex_unlock(&ctx->bitstream_mutex); - - if (coda_get_bitstream_payload(ctx) < 512 && - (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "bitstream payload: %d, skipping\n", - coda_get_bitstream_payload(ctx)); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); - return -EAGAIN; - } - - /* Run coda_start_decoding (again) if not yet initialized */ - if (!ctx->initialized) { - int ret = __coda_start_decoding(ctx); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); - return -EAGAIN; - } else { - ctx->initialized = 1; - } - } - - if (dev->devtype->product == CODA_960) - coda_set_gdi_regs(ctx); - - /* Set rotator output */ - picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) { - /* Switch Cr and Cb for YVU420 format */ - picture_cr = picture_y + stridey * height; - picture_cb = picture_cr + stridey / 2 * height / 2; - } else { - picture_cb = picture_y + stridey * height; - picture_cr = picture_cb + stridey / 2 * height / 2; - } - - if (dev->devtype->product == CODA_960) { - /* - * The CODA960 seems to have an internal list of buffers with - * 64 entries that includes the registered frame buffers as - * well as the rotator buffer output. - * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames. - */ - coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index, - CODA9_CMD_DEC_PIC_ROT_INDEX); - coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y); - coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB); - coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR); - coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE); - } else { - coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y); - coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB); - coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR); - coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE); - } - coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, - CODA_CMD_DEC_PIC_ROT_MODE); - - switch (dev->devtype->product) { - case CODA_DX6: - /* TBD */ - case CODA_7541: - coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); - break; - case CODA_960: - coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */ - break; - } - - coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); - - coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); - coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); - - if (dev->devtype->product != CODA_DX6) - coda_write(dev, ctx->iram_info.axi_sram_use, - CODA7_REG_BIT_AXI_SRAM_USE); - - coda_kfifo_sync_to_device_full(ctx); - coda_command_async(ctx, CODA_COMMAND_PIC_RUN); - - return 0; -} - -static int coda_prepare_encode(struct coda_ctx *ctx) -{ - struct coda_q_data *q_data_src, *q_data_dst; - struct vb2_buffer *src_buf, *dst_buf; - struct coda_dev *dev = ctx->dev; - int force_ipicture; - int quant_param = 0; - u32 picture_y, picture_cb, picture_cr; - u32 pic_stream_buffer_addr, pic_stream_buffer_size; - u32 dst_fourcc; - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; - - src_buf->v4l2_buf.sequence = ctx->osequence; - dst_buf->v4l2_buf.sequence = ctx->osequence; - ctx->osequence++; - - /* - * Workaround coda firmware BUG that only marks the first - * frame as IDR. This is a problem for some decoders that can't - * recover when a frame is lost. - */ - if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) { - src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; - src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; - } else { - src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; - src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; - } - - if (dev->devtype->product == CODA_960) - coda_set_gdi_regs(ctx); - - /* - * Copy headers at the beginning of the first frame for H.264 only. - * In MPEG4 they are already copied by the coda. - */ - if (src_buf->v4l2_buf.sequence == 0) { - pic_stream_buffer_addr = - vb2_dma_contig_plane_dma_addr(dst_buf, 0) + - ctx->vpu_header_size[0] + - ctx->vpu_header_size[1] + - ctx->vpu_header_size[2]; - pic_stream_buffer_size = CODA_MAX_FRAME_SIZE - - ctx->vpu_header_size[0] - - ctx->vpu_header_size[1] - - ctx->vpu_header_size[2]; - memcpy(vb2_plane_vaddr(dst_buf, 0), - &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); - memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0], - &ctx->vpu_header[1][0], ctx->vpu_header_size[1]); - memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] + - ctx->vpu_header_size[1], &ctx->vpu_header[2][0], - ctx->vpu_header_size[2]); - } else { - pic_stream_buffer_addr = - vb2_dma_contig_plane_dma_addr(dst_buf, 0); - pic_stream_buffer_size = CODA_MAX_FRAME_SIZE; - } - - if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { - force_ipicture = 1; - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - quant_param = ctx->params.h264_intra_qp; - break; - case V4L2_PIX_FMT_MPEG4: - quant_param = ctx->params.mpeg4_intra_qp; - break; - default: - v4l2_warn(&ctx->dev->v4l2_dev, - "cannot set intra qp, fmt not supported\n"); - break; - } - } else { - force_ipicture = 0; - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - quant_param = ctx->params.h264_inter_qp; - break; - case V4L2_PIX_FMT_MPEG4: - quant_param = ctx->params.mpeg4_inter_qp; - break; - default: - v4l2_warn(&ctx->dev->v4l2_dev, - "cannot set inter qp, fmt not supported\n"); - break; - } - } - - /* submit */ - coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); - coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); - - - picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0); - switch (q_data_src->fourcc) { - case V4L2_PIX_FMT_YVU420: - /* Switch Cb and Cr for YVU420 format */ - picture_cr = picture_y + q_data_src->bytesperline * - q_data_src->height; - picture_cb = picture_cr + q_data_src->bytesperline / 2 * - q_data_src->height / 2; - break; - case V4L2_PIX_FMT_YUV420: - default: - picture_cb = picture_y + q_data_src->bytesperline * - q_data_src->height; - picture_cr = picture_cb + q_data_src->bytesperline / 2 * - q_data_src->height / 2; - break; - } - - if (dev->devtype->product == CODA_960) { - coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); - coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE); - coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); - - coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y); - coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB); - coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR); - } else { - coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y); - coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB); - coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR); - } - coda_write(dev, force_ipicture << 1 & 0x2, - CODA_CMD_ENC_PIC_OPTION); - - coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); - coda_write(dev, pic_stream_buffer_size / 1024, - CODA_CMD_ENC_PIC_BB_SIZE); - - if (!ctx->streamon_out) { - /* After streamoff on the output side, set the stream end flag */ - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); - } - - if (dev->devtype->product != CODA_DX6) - coda_write(dev, ctx->iram_info.axi_sram_use, - CODA7_REG_BIT_AXI_SRAM_USE); - - coda_command_async(ctx, CODA_COMMAND_PIC_RUN); - - return 0; -} static void coda_device_run(void *m2m_priv) { @@ -1210,37 +707,6 @@ static void coda_device_run(void *m2m_priv) queue_work(dev->workqueue, &ctx->pic_run_work); } -static void coda_free_framebuffers(struct coda_ctx *ctx); -static void coda_free_context_buffers(struct coda_ctx *ctx); - -static void coda_seq_end_work(struct work_struct *work) -{ - struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); - struct coda_dev *dev = ctx->dev; - - mutex_lock(&ctx->buffer_mutex); - mutex_lock(&dev->coda_mutex); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__); - if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { - v4l2_err(&dev->v4l2_dev, - "CODA_COMMAND_SEQ_END failed\n"); - } - - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - - coda_free_framebuffers(ctx); - coda_free_context_buffers(ctx); - - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); -} - -static void coda_finish_decode(struct coda_ctx *ctx); -static void coda_finish_encode(struct coda_ctx *ctx); - static void coda_pic_run_work(struct work_struct *work) { struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work); @@ -1500,20 +966,8 @@ static void coda_buf_queue(struct vb2_buffer *vb) } } -static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) -{ - struct coda_dev *dev = ctx->dev; - u32 *p = ctx->parabuf.vaddr; - - if (dev->devtype->product == CODA_DX6) - p[index] = value; - else - p[index ^ 1] = value; -} - -static int coda_alloc_aux_buf(struct coda_dev *dev, - struct coda_aux_buf *buf, size_t size, - const char *name, struct dentry *parent) +int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, + size_t size, const char *name, struct dentry *parent) { buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr, GFP_KERNEL); @@ -1534,15 +988,8 @@ static int coda_alloc_aux_buf(struct coda_dev *dev, return 0; } -static inline int coda_alloc_context_buf(struct coda_ctx *ctx, - struct coda_aux_buf *buf, size_t size, - const char *name) -{ - return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); -} - -static void coda_free_aux_buf(struct coda_dev *dev, - struct coda_aux_buf *buf) +void coda_free_aux_buf(struct coda_dev *dev, + struct coda_aux_buf *buf) { if (buf->vaddr) { dma_free_coherent(&dev->plat_dev->dev, buf->size, @@ -1553,538 +1000,21 @@ static void coda_free_aux_buf(struct coda_dev *dev, debugfs_remove(buf->dentry); } -static void coda_free_framebuffers(struct coda_ctx *ctx) +static int coda_start_streaming(struct vb2_queue *q, unsigned int count) { - int i; + struct coda_ctx *ctx = vb2_get_drv_priv(q); + struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; + struct coda_q_data *q_data_src, *q_data_dst; + u32 dst_fourcc; + int ret = 0; - for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) - coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]); -} - -static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc) -{ - struct coda_dev *dev = ctx->dev; - int width, height; - dma_addr_t paddr; - int ysize; - int ret; - int i; - - if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || - ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) { - width = round_up(q_data->width, 16); - height = round_up(q_data->height, 16); - } else { - width = round_up(q_data->width, 8); - height = q_data->height; - } - ysize = width * height; - - /* Allocate frame buffers */ - for (i = 0; i < ctx->num_internal_frames; i++) { - size_t size; - char *name; - - size = ysize + ysize / 2; - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && - dev->devtype->product != CODA_DX6) - size += ysize / 4; - name = kasprintf(GFP_KERNEL, "fb%d", i); - ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], - size, name); - kfree(name); - if (ret < 0) { - coda_free_framebuffers(ctx); - return ret; - } - } - - /* Register frame buffers in the parameter buffer */ - for (i = 0; i < ctx->num_internal_frames; i++) { - paddr = ctx->internal_frames[i].paddr; - coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */ - coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */ - coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */ - - /* mvcol buffer for h.264 */ - if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && - dev->devtype->product != CODA_DX6) - coda_parabuf_write(ctx, 96 + i, - ctx->internal_frames[i].paddr + - ysize + ysize/4 + ysize/4); - } - - /* 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 + - ysize + ysize/4 + ysize/4); - - return 0; -} - -static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) -{ - phys_addr_t ret; - - size = round_up(size, 1024); - if (size > iram->remaining) - return 0; - iram->remaining -= size; - - ret = iram->next_paddr; - iram->next_paddr += size; - - return ret; -} - -static void coda_setup_iram(struct coda_ctx *ctx) -{ - struct coda_iram_info *iram_info = &ctx->iram_info; - struct coda_dev *dev = ctx->dev; - int mb_width; - int dbk_bits; - int bit_bits; - int ip_bits; - - memset(iram_info, 0, sizeof(*iram_info)); - iram_info->next_paddr = dev->iram.paddr; - iram_info->remaining = dev->iram.size; - - switch (dev->devtype->product) { - case CODA_7541: - dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; - bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; - ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; - break; - case CODA_960: - dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; - bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; - ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; - break; - default: /* CODA_DX6 */ - return; - } - - if (ctx->inst_type == CODA_INST_ENCODER) { - struct coda_q_data *q_data_src; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - mb_width = DIV_ROUND_UP(q_data_src->width, 16); - - /* Prioritize in case IRAM is too small for everything */ - if (dev->devtype->product == CODA_7541) { - iram_info->search_ram_size = round_up(mb_width * 16 * - 36 + 2048, 1024); - iram_info->search_ram_paddr = coda_iram_alloc(iram_info, - iram_info->search_ram_size); - if (!iram_info->search_ram_paddr) { - pr_err("IRAM is smaller than the search ram size\n"); - goto out; - } - iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE | - CODA7_USE_ME_ENABLE; - } - - /* Only H.264BP and H.263P3 are considered */ - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width); - if (!iram_info->buf_dbk_c_use) - goto out; - iram_info->axi_sram_use |= dbk_bits; - - iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_bit_use) - goto out; - iram_info->axi_sram_use |= bit_bits; - - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_ip_ac_dc_use) - goto out; - iram_info->axi_sram_use |= ip_bits; - - /* OVL and BTP disabled for encoder */ - } else if (ctx->inst_type == CODA_INST_DECODER) { - struct coda_q_data *q_data_dst; - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - mb_width = DIV_ROUND_UP(q_data_dst->width, 16); - - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_dbk_c_use) - goto out; - iram_info->axi_sram_use |= dbk_bits; - - iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_bit_use) - goto out; - iram_info->axi_sram_use |= bit_bits; - - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); - if (!iram_info->buf_ip_ac_dc_use) - goto out; - iram_info->axi_sram_use |= ip_bits; - - /* OVL and BTP unused as there is no VC1 support yet */ - } - -out: - if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "IRAM smaller than needed\n"); - - if (dev->devtype->product == CODA_7541) { - /* TODO - Enabling these causes picture errors on CODA7541 */ - if (ctx->inst_type == CODA_INST_DECODER) { - /* fw 1.4.50 */ - iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | - CODA7_USE_IP_ENABLE); - } else { - /* fw 13.4.29 */ - iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | - CODA7_USE_HOST_DBK_ENABLE | - CODA7_USE_IP_ENABLE | - CODA7_USE_DBK_ENABLE); - } - } -} - -static void coda_free_context_buffers(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - - coda_free_aux_buf(dev, &ctx->slicebuf); - coda_free_aux_buf(dev, &ctx->psbuf); - if (dev->devtype->product != CODA_DX6) - coda_free_aux_buf(dev, &ctx->workbuf); -} - -static int coda_alloc_context_buffers(struct coda_ctx *ctx, - struct coda_q_data *q_data) -{ - struct coda_dev *dev = ctx->dev; - size_t size; - int ret; - - if (dev->devtype->product == CODA_DX6) - return 0; - - if (ctx->psbuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n"); - return -EBUSY; - } - if (ctx->slicebuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n"); - return -EBUSY; - } - if (ctx->workbuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n"); - ret = -EBUSY; - return -ENOMEM; - } - - if (q_data->fourcc == V4L2_PIX_FMT_H264) { - /* worst case slice size */ - size = (DIV_ROUND_UP(q_data->width, 16) * - DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; - ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer", - ctx->slicebuf.size); - return ret; - } - } - - if (dev->devtype->product == CODA_7541) { - ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer"); - goto err; - } - } - - size = dev->devtype->workbuf_size; - if (dev->devtype->product == CODA_960 && - q_data->fourcc == V4L2_PIX_FMT_H264) - size += CODA9_PS_SAVE_SIZE; - ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer", - ctx->workbuf.size); - goto err; - } - - return 0; - -err: - coda_free_context_buffers(ctx); - return ret; -} - -static int __coda_start_decoding(struct coda_ctx *ctx) -{ - struct coda_q_data *q_data_src, *q_data_dst; - u32 bitstream_buf, bitstream_size; - struct coda_dev *dev = ctx->dev; - int width, height; - u32 src_fourcc; - u32 val; - int ret; - - /* Start decoding */ - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - bitstream_buf = ctx->bitstream.paddr; - bitstream_size = ctx->bitstream.size; - src_fourcc = q_data_src->fourcc; - - /* Allocate per-instance buffers */ - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); - - /* Update coda bitstream read and write pointers from kfifo */ - coda_kfifo_sync_to_device_full(ctx); - - ctx->display_idx = -1; - ctx->frm_dis_flg = 0; - coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - - coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE, - CODA_REG_BIT_BIT_STREAM_PARAM); - - coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); - coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); - val = 0; - if ((dev->devtype->product == CODA_7541) || - (dev->devtype->product == CODA_960)) - val |= CODA_REORDER_ENABLE; - coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); - - ctx->params.codec_mode = ctx->codec->mode; - if (dev->devtype->product == CODA_960 && - src_fourcc == V4L2_PIX_FMT_MPEG4) - ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; - else - ctx->params.codec_mode_aux = 0; - if (src_fourcc == V4L2_PIX_FMT_H264) { - if (dev->devtype->product == CODA_7541) { - coda_write(dev, ctx->psbuf.paddr, - CODA_CMD_DEC_SEQ_PS_BB_START); - coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), - CODA_CMD_DEC_SEQ_PS_BB_SIZE); - } - if (dev->devtype->product == CODA_960) { - coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); - coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); - } - } - if (dev->devtype->product != CODA_960) { - coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); - } - - if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) { - v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); - coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); - return -ETIMEDOUT; - } - - /* Update kfifo out pointer from coda bitstream read pointer */ - coda_kfifo_sync_from_device(ctx); - - coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); - - if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { - v4l2_err(&dev->v4l2_dev, - "CODA_COMMAND_SEQ_INIT failed, error code = %d\n", - coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); - return -EAGAIN; - } - - val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); - if (dev->devtype->product == CODA_DX6) { - width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; - height = val & CODADX6_PICHEIGHT_MASK; - } else { - width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; - height = val & CODA7_PICHEIGHT_MASK; - } - - if (width > q_data_dst->width || height > q_data_dst->height) { - v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", - width, height, q_data_dst->width, q_data_dst->height); - return -EINVAL; - } - - width = round_up(width, 16); - height = round_up(height, 16); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n", - __func__, ctx->idx, width, height); - - ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); - if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { - v4l2_err(&dev->v4l2_dev, - "not enough framebuffers to decode (%d < %d)\n", - CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); - return -EINVAL; - } - - if (src_fourcc == V4L2_PIX_FMT_H264) { - u32 left_right; - u32 top_bottom; - - left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); - top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); - - q_data_dst->rect.left = (left_right >> 10) & 0x3ff; - q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; - q_data_dst->rect.width = width - q_data_dst->rect.left - - (left_right & 0x3ff); - q_data_dst->rect.height = height - q_data_dst->rect.top - - (top_bottom & 0x3ff); - } - - ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); - if (ret < 0) - return ret; - - /* Tell the decoder how many frame buffers we allocated. */ - coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE); - - if (dev->devtype->product != CODA_DX6) { - /* Set secondary AXI IRAM */ - coda_setup_iram(ctx); - - coda_write(dev, ctx->iram_info.buf_bit_use, - CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); - coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, - CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_y_use, - CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_c_use, - 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) - coda_write(dev, ctx->iram_info.buf_btp_use, - CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); - } - - if (dev->devtype->product == CODA_960) { - coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); - - coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE); - coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET | - 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | - 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET | - 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET, - CODA9_CMD_SET_FRAME_CACHE_CONFIG); - } - - if (src_fourcc == V4L2_PIX_FMT_H264) { - coda_write(dev, ctx->slicebuf.paddr, - CODA_CMD_SET_FRAME_SLICE_BB_START); - coda_write(dev, ctx->slicebuf.size / 1024, - CODA_CMD_SET_FRAME_SLICE_BB_SIZE); - } - - if (dev->devtype->product == CODA_7541) { - int max_mb_x = 1920 / 16; - int max_mb_y = 1088 / 16; - int max_mb_num = max_mb_x * max_mb_y; - - coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, - CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); - } else if (dev->devtype->product == CODA_960) { - int max_mb_x = 1920 / 16; - int max_mb_y = 1088 / 16; - int max_mb_num = max_mb_x * max_mb_y; - - coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, - CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); - } - - if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { - v4l2_err(&ctx->dev->v4l2_dev, - "CODA_COMMAND_SET_FRAME_BUF timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int coda_start_decoding(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - int ret; - - mutex_lock(&dev->coda_mutex); - ret = __coda_start_decoding(ctx); - mutex_unlock(&dev->coda_mutex); - - return ret; -} - -static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf, - int header_code, u8 *header, int *size) -{ - struct coda_dev *dev = ctx->dev; - size_t bufsize; - int ret; - int i; - - if (dev->devtype->product == CODA_960) - memset(vb2_plane_vaddr(buf, 0), 0, 64); - - coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), - CODA_CMD_ENC_HEADER_BB_START); - bufsize = vb2_plane_size(buf, 0); - if (dev->devtype->product == CODA_960) - bufsize /= 1024; - coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); - coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); - ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); - return ret; - } - - if (dev->devtype->product == CODA_960) { - for (i = 63; i > 0; i--) - if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0) - break; - *size = i + 1; - } else { - *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - - coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); - } - memcpy(header, vb2_plane_vaddr(buf, 0), *size); - - return 0; -} - -static int coda_start_encoding(struct coda_ctx *ctx); - -static int coda_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct coda_ctx *ctx = vb2_get_drv_priv(q); - struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; - struct coda_q_data *q_data_src, *q_data_dst; - u32 dst_fourcc; - int ret = 0; - - 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) { - /* copy the buffers that where queued before streamon */ - mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx); - mutex_unlock(&ctx->bitstream_mutex); + 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) { + /* copy the buffers that where queued before streamon */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx); + mutex_unlock(&ctx->bitstream_mutex); if (coda_get_bitstream_payload(ctx) < 512) return -EINVAL; @@ -2132,337 +1062,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) return ret; } -static int coda_start_encoding(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - struct coda_q_data *q_data_src, *q_data_dst; - u32 bitstream_buf, bitstream_size; - struct vb2_buffer *buf; - int gamma, ret, value; - u32 dst_fourcc; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; - - /* Allocate per-instance buffers */ - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - - buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); - bitstream_size = q_data_dst->sizeimage; - - if (!coda_is_initialized(dev)) { - v4l2_err(v4l2_dev, "coda is not initialized.\n"); - return -EFAULT; - } - - mutex_lock(&dev->coda_mutex); - - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); - coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); - coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); - switch (dev->devtype->product) { - case CODA_DX6: - coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | - CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); - break; - case CODA_960: - coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); - /* fallthrough */ - case CODA_7541: - coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | - CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); - break; - } - - value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL); - value &= ~(1 << 2 | 0x7 << 9); - ctx->frame_mem_ctrl = value; - coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL); - - if (dev->devtype->product == CODA_DX6) { - /* Configure the coda */ - coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); - } - - /* Could set rotation here if needed */ - switch (dev->devtype->product) { - case CODA_DX6: - value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET; - value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; - break; - case CODA_7541: - if (dst_fourcc == V4L2_PIX_FMT_H264) { - value = (round_up(q_data_src->width, 16) & - CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; - value |= (round_up(q_data_src->height, 16) & - CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; - break; - } - /* fallthrough */ - case CODA_960: - value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; - value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); - coda_write(dev, ctx->params.framerate, - CODA_CMD_ENC_SEQ_SRC_F_RATE); - - ctx->params.codec_mode = ctx->codec->mode; - switch (dst_fourcc) { - case V4L2_PIX_FMT_MPEG4: - if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); - else - coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); - coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); - break; - case V4L2_PIX_FMT_H264: - if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); - else - coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); - if (ctx->params.h264_deblk_enabled) { - value = ((ctx->params.h264_deblk_alpha & - CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | - ((ctx->params.h264_deblk_beta & - CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET); - } else { - value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); - break; - default: - v4l2_err(v4l2_dev, - "dst format (0x%08x) invalid.\n", dst_fourcc); - ret = -EINVAL; - goto out; - } - - switch (ctx->params.slice_mode) { - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: - value = 0; - break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: - value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; - value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: - value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; - value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); - value = ctx->params.gop_size & CODA_GOP_SIZE_MASK; - coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); - - if (ctx->params.bitrate) { - /* Rate control enabled */ - value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; - value |= 1 & CODA_RATECONTROL_ENABLE_MASK; - if (dev->devtype->product == CODA_960) - value |= BIT(31); /* disable autoskip */ - } else { - value = 0; - } - 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.intra_refresh, - CODA_CMD_ENC_SEQ_INTRA_REFRESH); - - coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); - coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); - - - value = 0; - if (dev->devtype->product == CODA_960) - gamma = CODA9_DEFAULT_GAMMA; - else - gamma = CODA_DEFAULT_GAMMA; - if (gamma > 0) { - coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, - CODA_CMD_ENC_SEQ_RC_GAMMA); - } - - if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { - coda_write(dev, - ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | - ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, - CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); - } - if (dev->devtype->product == CODA_960) { - if (ctx->params.h264_max_qp) - value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; - if (CODA_DEFAULT_GAMMA > 0) - value |= 1 << CODA9_OPTION_GAMMA_OFFSET; - } else { - if (CODA_DEFAULT_GAMMA > 0) { - if (dev->devtype->product == CODA_DX6) - value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; - else - value |= 1 << CODA7_OPTION_GAMMA_OFFSET; - } - if (ctx->params.h264_min_qp) - value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; - if (ctx->params.h264_max_qp) - value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; - } - coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); - - coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); - - coda_setup_iram(ctx); - - if (dst_fourcc == V4L2_PIX_FMT_H264) { - switch (dev->devtype->product) { - case CODA_DX6: - value = FMO_SLICE_SAVE_BUF_SIZE << 7; - coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); - break; - case CODA_7541: - coda_write(dev, ctx->iram_info.search_ram_paddr, - CODA7_CMD_ENC_SEQ_SEARCH_BASE); - coda_write(dev, ctx->iram_info.search_ram_size, - CODA7_CMD_ENC_SEQ_SEARCH_SIZE); - break; - case CODA_960: - coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); - coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); - } - } - - ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); - if (ret < 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); - goto out; - } - - if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); - ret = -EFAULT; - goto out; - } - - if (dev->devtype->product == CODA_960) - ctx->num_internal_frames = 4; - else - ctx->num_internal_frames = 2; - ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); - if (ret < 0) { - v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); - goto out; - } - - coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, q_data_src->bytesperline, - CODA_CMD_SET_FRAME_BUF_STRIDE); - if (dev->devtype->product == CODA_7541) { - coda_write(dev, q_data_src->bytesperline, - CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); - } - if (dev->devtype->product != CODA_DX6) { - coda_write(dev, ctx->iram_info.buf_bit_use, - CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); - coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, - CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_y_use, - CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); - coda_write(dev, ctx->iram_info.buf_dbk_c_use, - 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) { - coda_write(dev, ctx->iram_info.buf_btp_use, - CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); - - /* FIXME */ - coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); - coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B); - } - } - - ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); - if (ret < 0) { - v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); - goto out; - } - - /* Save stream headers */ - buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - switch (dst_fourcc) { - case V4L2_PIX_FMT_H264: - /* - * Get SPS in the first frame and copy it to an - * intermediate buffer. - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, - &ctx->vpu_header[0][0], - &ctx->vpu_header_size[0]); - if (ret < 0) - goto out; - - /* - * Get PPS in the first frame and copy it to an - * intermediate buffer. - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, - &ctx->vpu_header[1][0], - &ctx->vpu_header_size[1]); - if (ret < 0) - goto out; - - /* - * Length of H.264 headers is variable and thus it might not be - * aligned for the coda to append the encoded frame. In that is - * the case a filler NAL must be added to header 2. - */ - ctx->vpu_header_size[2] = coda_h264_padding( - (ctx->vpu_header_size[0] + - ctx->vpu_header_size[1]), - ctx->vpu_header[2]); - break; - case V4L2_PIX_FMT_MPEG4: - /* - * Get VOS in the first frame and copy it to an - * intermediate buffer - */ - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, - &ctx->vpu_header[0][0], - &ctx->vpu_header_size[0]); - if (ret < 0) - goto out; - - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, - &ctx->vpu_header[1][0], - &ctx->vpu_header_size[1]); - if (ret < 0) - goto out; - - ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, - &ctx->vpu_header[2][0], - &ctx->vpu_header_size[2]); - if (ret < 0) - goto out; - break; - default: - /* No more formats need to save headers at the moment */ - break; - } - -out: - mutex_unlock(&dev->coda_mutex); - return ret; -} - static void coda_stop_streaming(struct vb2_queue *q) { struct coda_ctx *ctx = vb2_get_drv_priv(q); @@ -2662,8 +1261,8 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) return vb2_queue_init(vq); } -static int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) +int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) { int ret; @@ -2682,8 +1281,8 @@ static int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, return coda_queue_init(priv, dst_vq); } -static int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) +int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) { int ret; @@ -2843,38 +1442,14 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, return ret; } -static void coda_bit_release(struct coda_ctx *ctx) -{ - coda_free_framebuffers(ctx); - coda_free_context_buffers(ctx); -} - -struct coda_context_ops coda_encode_ops = { - .queue_init = coda_encoder_queue_init, - .start_streaming = coda_start_encoding, - .prepare_run = coda_prepare_encode, - .finish_run = coda_finish_encode, - .seq_end_work = coda_seq_end_work, - .release = coda_bit_release, -}; - -struct coda_context_ops coda_decode_ops = { - .queue_init = coda_decoder_queue_init, - .start_streaming = coda_start_decoding, - .prepare_run = coda_prepare_decode, - .finish_run = coda_finish_decode, - .seq_end_work = coda_seq_end_work, - .release = coda_bit_release, -}; - static int coda_encoder_open(struct file *file) { - return coda_open(file, CODA_INST_ENCODER, &coda_encode_ops); + return coda_open(file, CODA_INST_ENCODER, &coda_bit_encode_ops); } static int coda_decoder_open(struct file *file) { - return coda_open(file, CODA_INST_DECODER, &coda_decode_ops); + return coda_open(file, CODA_INST_DECODER, &coda_bit_decode_ops); } static int coda_release(struct file *file) @@ -2938,316 +1513,6 @@ static const struct v4l2_file_operations coda_decoder_fops = { .mmap = v4l2_m2m_fop_mmap, }; -static void coda_finish_decode(struct coda_ctx *ctx) -{ - struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data_src; - struct coda_q_data *q_data_dst; - struct vb2_buffer *dst_buf; - struct coda_timestamp *ts; - int width, height; - int decoded_idx; - int display_idx; - u32 src_fourcc; - int success; - u32 err_mb; - u32 val; - - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - /* Update kfifo out pointer from coda bitstream read pointer */ - coda_kfifo_sync_from_device(ctx); - - /* - * in stream-end mode, the read pointer can overshoot the write pointer - * by up to 512 bytes - */ - if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { - if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512) - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); - } - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - src_fourcc = q_data_src->fourcc; - - val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); - if (val != 1) - pr_err("DEC_PIC_SUCCESS = %d\n", val); - - success = val & 0x1; - if (!success) - v4l2_err(&dev->v4l2_dev, "decode failed\n"); - - if (src_fourcc == V4L2_PIX_FMT_H264) { - if (val & (1 << 3)) - v4l2_err(&dev->v4l2_dev, - "insufficient PS buffer space (%d bytes)\n", - ctx->psbuf.size); - if (val & (1 << 2)) - v4l2_err(&dev->v4l2_dev, - "insufficient slice buffer space (%d bytes)\n", - ctx->slicebuf.size); - } - - val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); - width = (val >> 16) & 0xffff; - height = val & 0xffff; - - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - /* frame crop information */ - if (src_fourcc == V4L2_PIX_FMT_H264) { - u32 left_right; - u32 top_bottom; - - left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); - top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); - - if (left_right == 0xffffffff && top_bottom == 0xffffffff) { - /* Keep current crop information */ - } else { - struct v4l2_rect *rect = &q_data_dst->rect; - - rect->left = left_right >> 16 & 0xffff; - rect->top = top_bottom >> 16 & 0xffff; - rect->width = width - rect->left - - (left_right & 0xffff); - rect->height = height - rect->top - - (top_bottom & 0xffff); - } - } else { - /* no cropping */ - } - - err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); - if (err_mb > 0) - v4l2_err(&dev->v4l2_dev, - "errors in %d macroblocks\n", err_mb); - - if (dev->devtype->product == CODA_7541) { - val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); - if (val == 0) { - /* not enough bitstream data */ - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "prescan failed: %d\n", val); - ctx->hold = true; - return; - } - } - - ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - - /* - * The previous display frame was copied out by the rotator, - * now it can be overwritten again - */ - if (ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) { - ctx->frm_dis_flg &= ~(1 << ctx->display_idx); - coda_write(dev, ctx->frm_dis_flg, - CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - } - - /* - * The index of the last decoded frame, not necessarily in - * display order, and the index of the next display frame. - * The latter could have been decoded in a previous run. - */ - decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); - display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); - - if (decoded_idx == -1) { - /* no frame was decoded, but we might have a display frame */ - if (display_idx >= 0 && display_idx < ctx->num_internal_frames) - ctx->sequence_offset++; - else if (ctx->display_idx < 0) - ctx->hold = true; - } else if (decoded_idx == -2) { - /* no frame was decoded, we still return the remaining buffers */ - } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { - v4l2_err(&dev->v4l2_dev, - "decoded frame index out of range: %d\n", decoded_idx); - } else { - ts = list_first_entry(&ctx->timestamp_list, - struct coda_timestamp, list); - list_del(&ts->list); - val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; - val -= ctx->sequence_offset; - if (val != (ts->sequence & 0xffff)) { - v4l2_err(&dev->v4l2_dev, - "sequence number mismatch (%d(%d) != %d)\n", - val, ctx->sequence_offset, ts->sequence); - } - ctx->frame_timestamps[decoded_idx] = *ts; - kfree(ts); - - val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; - if (val == 0) - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; - else if (val == 1) - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME; - else - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME; - - ctx->frame_errors[decoded_idx] = err_mb; - } - - if (display_idx == -1) { - /* - * no more frames to be decoded, but there could still - * be rotator output to dequeue - */ - ctx->hold = true; - } else if (display_idx == -3) { - /* possibly prescan failure */ - } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { - v4l2_err(&dev->v4l2_dev, - "presentation frame index out of range: %d\n", - display_idx); - } - - /* If a frame was copied out, return it */ - if (ctx->display_idx >= 0 && - ctx->display_idx < ctx->num_internal_frames) { - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - dst_buf->v4l2_buf.sequence = ctx->osequence++; - - dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | - V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_BFRAME); - dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx]; - ts = &ctx->frame_timestamps[ctx->display_idx]; - dst_buf->v4l2_buf.timecode = ts->timecode; - dst_buf->v4l2_buf.timestamp = ts->timestamp; - - vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2); - - v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: decoding frame (%d) (%s)\n", - dst_buf->v4l2_buf.sequence, - (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? - "KEYFRAME" : "PFRAME"); - } else { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: no frame decoded\n"); - } - - /* The rotator will copy the current display frame next time */ - ctx->display_idx = display_idx; -} - -static void coda_finish_encode(struct coda_ctx *ctx) -{ - struct vb2_buffer *src_buf, *dst_buf; - struct coda_dev *dev = ctx->dev; - u32 wr_ptr, start_ptr; - - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - /* Get results from the coda */ - start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); - wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); - - /* Calculate bytesused field */ - if (dst_buf->v4l2_buf.sequence == 0) { - vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr + - ctx->vpu_header_size[0] + - ctx->vpu_header_size[1] + - ctx->vpu_header_size[2]); - } else { - vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr); - } - - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n", - wr_ptr - start_ptr); - - coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); - coda_read(dev, CODA_RET_ENC_PIC_FLAG); - - if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) { - dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; - dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; - } else { - dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; - dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; - } - - dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp; - dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->v4l2_buf.flags |= - src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; - - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); - - ctx->gopcounter--; - if (ctx->gopcounter < 0) - ctx->gopcounter = ctx->params.gop_size - 1; - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: encoding frame (%d) (%s)\n", - dst_buf->v4l2_buf.sequence, - (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? - "KEYFRAME" : "PFRAME"); -} - -static irqreturn_t coda_irq_handler(int irq, void *data) -{ - struct coda_dev *dev = data; - struct coda_ctx *ctx; - - /* read status register to attend the IRQ */ - coda_read(dev, CODA_REG_BIT_INT_STATUS); - coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, - CODA_REG_BIT_INT_CLEAR); - - ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); - if (ctx == NULL) { - v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); - mutex_unlock(&dev->coda_mutex); - return IRQ_HANDLED; - } - - if (ctx->aborting) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "task has been aborted\n"); - } - - if (coda_isbusy(ctx->dev)) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "coda is still busy!!!!\n"); - return IRQ_NONE; - } - - complete(&ctx->completion); - - return IRQ_HANDLED; -} - -static u32 coda_supported_firmwares[] = { - CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), - CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), - CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), -}; - -static bool coda_firmware_supported(u32 vernum) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) - if (vernum == coda_supported_firmwares[i]) - return true; - return false; -} - static int coda_hw_init(struct coda_dev *dev) { u32 data; @@ -3344,76 +1609,6 @@ static int coda_hw_init(struct coda_dev *dev) return ret; } -static int coda_check_firmware(struct coda_dev *dev) -{ - u16 product, major, minor, release; - u32 data; - int ret; - - ret = clk_prepare_enable(dev->clk_per); - if (ret) - goto err_clk_per; - - ret = clk_prepare_enable(dev->clk_ahb); - if (ret) - goto err_clk_ahb; - - coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); - coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); - coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); - coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); - coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); - if (coda_wait_timeout(dev)) { - v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); - ret = -EIO; - goto err_run_cmd; - } - - if (dev->devtype->product == CODA_960) { - data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); - v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", - data); - } - - /* Check we are compatible with the loaded firmware */ - data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); - product = CODA_FIRMWARE_PRODUCT(data); - major = CODA_FIRMWARE_MAJOR(data); - minor = CODA_FIRMWARE_MINOR(data); - release = CODA_FIRMWARE_RELEASE(data); - - clk_disable_unprepare(dev->clk_per); - clk_disable_unprepare(dev->clk_ahb); - - if (product != dev->devtype->product) { - v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s," - " Version: %u.%u.%u\n", - coda_product_name(dev->devtype->product), - coda_product_name(product), major, minor, release); - return -EINVAL; - } - - v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", - coda_product_name(product)); - - if (coda_firmware_supported(data)) { - v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", - major, minor, release); - } else { - v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: " - "%u.%u.%u\n", major, minor, release); - } - - return 0; - -err_run_cmd: - clk_disable_unprepare(dev->clk_ahb); -err_clk_ahb: - clk_disable_unprepare(dev->clk_per); -err_clk_per: - return ret; -} - static int coda_register_device(struct coda_dev *dev, struct video_device *vfd) { vfd->release = video_device_release_empty, diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 84e0829afc85..bbc18c0dacd9 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -228,4 +228,60 @@ struct coda_ctx { struct dentry *debugfs_entry; }; +extern int coda_debug; + +void coda_write(struct coda_dev *dev, u32 data, u32 reg); +unsigned int coda_read(struct coda_dev *dev, u32 reg); + +int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, + size_t size, const char *name, struct dentry *parent); +void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf); + +static inline int coda_alloc_context_buf(struct coda_ctx *ctx, + struct coda_aux_buf *buf, size_t size, + const char *name) +{ + return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); +} + +int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); +int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); + +int coda_hw_reset(struct coda_ctx *ctx); + +void coda_fill_bitstream(struct coda_ctx *ctx); + +void coda_set_gdi_regs(struct coda_ctx *ctx); + +static inline struct coda_q_data *get_q_data(struct coda_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &(ctx->q_data[V4L2_M2M_SRC]); + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &(ctx->q_data[V4L2_M2M_DST]); + default: + return NULL; + } +} + +const char *coda_product_name(int product); + +int coda_check_firmware(struct coda_dev *dev); + +static inline int coda_get_bitstream_payload(struct coda_ctx *ctx) +{ + return kfifo_len(&ctx->bitstream_fifo); +} + +void coda_bit_stream_end_flag(struct coda_ctx *ctx); + int coda_h264_padding(int size, char *p); + +extern const struct coda_context_ops coda_bit_encode_ops; +extern const struct coda_context_ops coda_bit_decode_ops; + +irqreturn_t coda_irq_handler(int irq, void *data); -- GitLab From 2c3759d406ded38b88992cb4e423ce232112001a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:06 -0300 Subject: [PATCH 0541/5088] [media] coda: include header for memcpy coda_h264_padding uses memcpy, we should include string.h for that. Reported-by: Ian Jamison Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-h264.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c index 0b2fdbeea7cb..456773af1f1d 100644 --- a/drivers/media/platform/coda/coda-h264.c +++ b/drivers/media/platform/coda/coda-h264.c @@ -12,6 +12,7 @@ */ #include +#include static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; -- GitLab From 5727a5a4a1d89a8bf1442e7b0fd83de63512a1b6 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:08 -0300 Subject: [PATCH 0542/5088] [media] coda: remove unnecessary peek at next destination buffer from coda_finish_decode The return value of this call to v4l2_m2m_next_dst_buf() is never used. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 1d2716d564a1..cc9afb733b48 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1580,8 +1580,6 @@ static void coda_finish_decode(struct coda_ctx *ctx) u32 err_mb; u32 val; - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - /* Update kfifo out pointer from coda bitstream read pointer */ coda_kfifo_sync_from_device(ctx); -- GitLab From 540b72e415d6033b72037dbdb1f6c00516034250 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:09 -0300 Subject: [PATCH 0543/5088] [media] coda: request BIT processor interrupt by name Request the main coda interrupt using its name, "bit", if available. Fall back to requesting the first interrupt for backwards compatibility. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index dc9740d0ea5e..86fc527a7782 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1835,7 +1835,9 @@ static int coda_probe(struct platform_device *pdev) return PTR_ERR(dev->regs_base); /* IRQ */ - irq = platform_get_irq(pdev, 0); + irq = platform_get_irq_byname(pdev, "bit"); + if (irq < 0) + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get irq resource\n"); return irq; -- GitLab From b906352c23388837a643720d8548ae9459b5ed76 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:10 -0300 Subject: [PATCH 0544/5088] [media] coda: dequeue buffers if start_streaming fails Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 34 +++++++++++++++++------ 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 86fc527a7782..1e938895f5f9 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1005,6 +1005,7 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) struct coda_ctx *ctx = vb2_get_drv_priv(q); struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; struct coda_q_data *q_data_src, *q_data_dst; + struct vb2_buffer *buf; u32 dst_fourcc; int ret = 0; @@ -1016,17 +1017,23 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) coda_fill_bitstream(ctx); mutex_unlock(&ctx->bitstream_mutex); - if (coda_get_bitstream_payload(ctx) < 512) - return -EINVAL; + if (coda_get_bitstream_payload(ctx) < 512) { + ret = -EINVAL; + goto err; + } } else { - if (count < 1) - return -EINVAL; + if (count < 1) { + ret = -EINVAL; + goto err; + } } ctx->streamon_out = 1; } else { - if (count < 1) - return -EINVAL; + if (count < 1) { + ret = -EINVAL; + goto err; + } ctx->streamon_cap = 1; } @@ -1047,7 +1054,8 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) q_data_dst->fourcc); if (!ctx->codec) { v4l2_err(v4l2_dev, "couldn't tell instance type.\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } ret = ctx->ops->start_streaming(ctx); @@ -1055,11 +1063,21 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) if (ret == -EAGAIN) return 0; else if (ret < 0) - return ret; + goto err; } ctx->initialized = 1; return ret; + +err: + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED); + } else { + while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED); + } + return ret; } static void coda_stop_streaming(struct vb2_queue *q) -- GitLab From 4a31b52fca20d1fc0abe0d0f5489b9eec2760219 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:11 -0300 Subject: [PATCH 0545/5088] [media] coda: dequeue buffers on streamoff This is needed to decrease the q->owned_by_drv_count to zero before __vb2_queue_cancel is called, to avoid the WARN_ON therein. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 1e938895f5f9..6760e346f969 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1084,6 +1084,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; if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, @@ -1091,7 +1092,11 @@ static void coda_stop_streaming(struct vb2_queue *q) ctx->streamon_out = 0; coda_bit_stream_end_flag(ctx); + ctx->isequence = 0; + + while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); } else { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s: capture\n", __func__); @@ -1099,6 +1104,9 @@ static void coda_stop_streaming(struct vb2_queue *q) ctx->osequence = 0; ctx->sequence_offset = 0; + + while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); } if (!ctx->streamon_out && !ctx->streamon_cap) { -- GitLab From fcf59764b99c7daa9b0876fe65d1393e6b759673 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:12 -0300 Subject: [PATCH 0546/5088] [media] coda: skip calling coda_find_codec in encoder try_fmt_vid_out We know that it will return NULL in this case, so we can just as well skip it altogether. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 6760e346f969..4e85e387f905 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -426,14 +426,15 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - const struct coda_codec *codec; + const struct coda_codec *codec = NULL; /* Determine codec by encoded format, returns NULL if raw or invalid */ - codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, - V4L2_PIX_FMT_YUV420); - if (!codec && ctx->inst_type == CODA_INST_DECODER) { - codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264, + if (ctx->inst_type == CODA_INST_DECODER) { + codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, V4L2_PIX_FMT_YUV420); + if (!codec) + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264, + V4L2_PIX_FMT_YUV420); if (!codec) return -EINVAL; } -- GitLab From 8be31c898deea6ac57bc1dc4973b88c931c82980 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:13 -0300 Subject: [PATCH 0547/5088] [media] coda: allow running coda without iram on mx6dl Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 3 +++ drivers/media/platform/coda/coda-common.c | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index cc9afb733b48..fddd10d53558 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -474,6 +474,9 @@ static void coda_setup_iram(struct coda_ctx *ctx) iram_info->next_paddr = dev->iram.paddr; iram_info->remaining = dev->iram.size; + if (!dev->iram.vaddr) + return; + switch (dev->devtype->product) { case CODA_7541: dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 4e85e387f905..3bf30b8215dd 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1947,15 +1947,15 @@ static int coda_probe(struct platform_device *pdev) dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size, &dev->iram.paddr); if (!dev->iram.vaddr) { - dev_err(&pdev->dev, "unable to alloc iram\n"); - return -ENOMEM; + dev_warn(&pdev->dev, "unable to alloc iram\n"); + } else { + dev->iram.blob.data = dev->iram.vaddr; + dev->iram.blob.size = dev->iram.size; + dev->iram.dentry = debugfs_create_blob("iram", 0644, + dev->debugfs_root, + &dev->iram.blob); } - dev->iram.blob.data = dev->iram.vaddr; - dev->iram.blob.size = dev->iram.size; - dev->iram.dentry = debugfs_create_blob("iram", 0644, dev->debugfs_root, - &dev->iram.blob); - dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1); if (!dev->workqueue) { dev_err(&pdev->dev, "unable to alloc workqueue\n"); -- GitLab From b0ed05b9025528b8480ba12d8e706eef6fe1dbc5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:14 -0300 Subject: [PATCH 0548/5088] [media] coda: increase max vertical frame size to 1088 This patch increases the maximum vertical frame size reported by enum_fmt and accepted by try_fmt/s_fmt from 1080 to 1088. Since for 16x16-pixel macroblocks 1080p will be rounded up to this anyway, we may as well admit that we support it. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3bf30b8215dd..6020e336c998 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -39,7 +39,6 @@ #include #include "coda.h" -#include "coda_regs.h" #define CODA_NAME "coda" @@ -122,15 +121,15 @@ static const struct coda_codec codadx6_codecs[] = { static const struct coda_codec coda7_codecs[] = { CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), - CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), - CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080), + CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), }; static const struct coda_codec coda9_codecs[] = { - CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1080), - CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1080), - CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080), - CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080), + CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1088), + CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1088), + CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), }; static bool coda_format_is_yuv(u32 fourcc) -- GitLab From d60b18ba318ec4fb32851ad72f33e1dbc1b641f0 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:15 -0300 Subject: [PATCH 0549/5088] [media] coda: add an intermediate debug level Dumping all register accesses drowns other debugging messages in the log. Add a less verbose debug level. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 6020e336c998..73114529b2c4 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -58,7 +58,7 @@ int coda_debug; module_param(coda_debug, int, 0644); -MODULE_PARM_DESC(coda_debug, "Debug level (0-1)"); +MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); struct coda_fmt { char *name; @@ -67,7 +67,7 @@ struct coda_fmt { void coda_write(struct coda_dev *dev, u32 data, u32 reg) { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + v4l2_dbg(2, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); writel(data, dev->regs_base + reg); } @@ -76,7 +76,7 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg) { u32 data; data = readl(dev->regs_base + reg); - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + v4l2_dbg(2, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); return data; } -- GitLab From 68fc31c5d29690685476ea3fbc7da8876f227792 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:16 -0300 Subject: [PATCH 0550/5088] [media] coda: improve allocation error messages Produce some error messages when internal buffer allocation fails, for example because the CMA region is too small. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 4 +++- drivers/media/platform/coda/coda-common.c | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index fddd10d53558..529cc3e8acb0 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1378,8 +1378,10 @@ static int __coda_start_decoding(struct coda_ctx *ctx) } ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); - if (ret < 0) + if (ret < 0) { + v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n"); return ret; + } /* Tell the decoder how many frame buffers we allocated. */ coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 73114529b2c4..0f8a2c970405 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -971,8 +971,12 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, { buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr, GFP_KERNEL); - if (!buf->vaddr) + if (!buf->vaddr) { + v4l2_err(&dev->v4l2_dev, + "Failed to allocate %s buffer of size %u\n", + name, size); return -ENOMEM; + } buf->size = size; -- GitLab From 18fd0cceb99fdfd551bb6520703f8e1be4f3f364 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:17 -0300 Subject: [PATCH 0551/5088] [media] coda: fix timestamp list handling Lock modification of the timestamp list with bitstream_mutex and do not try to remove a timestamp element if the list is empty. This can happen if the userspace feeds us garbage or multiple encoded frames in a single buffer. Signed-off-by: Michael Olbrich Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 28 +++++++++++++++-------- drivers/media/platform/coda/coda-common.c | 2 ++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 529cc3e8acb0..18fa369d204d 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1699,18 +1699,28 @@ static void coda_finish_decode(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "decoded frame index out of range: %d\n", decoded_idx); } else { - ts = list_first_entry(&ctx->timestamp_list, - struct coda_timestamp, list); - list_del(&ts->list); val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; val -= ctx->sequence_offset; - if (val != (ts->sequence & 0xffff)) { - v4l2_err(&dev->v4l2_dev, - "sequence number mismatch (%d(%d) != %d)\n", - val, ctx->sequence_offset, ts->sequence); + mutex_lock(&ctx->bitstream_mutex); + if (!list_empty(&ctx->timestamp_list)) { + ts = list_first_entry(&ctx->timestamp_list, + struct coda_timestamp, list); + list_del(&ts->list); + if (val != (ts->sequence & 0xffff)) { + v4l2_err(&dev->v4l2_dev, + "sequence number mismatch (%d(%d) != %d)\n", + val, ctx->sequence_offset, + ts->sequence); + } + ctx->frame_timestamps[decoded_idx] = *ts; + kfree(ts); + } else { + v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); + memset(&ctx->frame_timestamps[decoded_idx], 0, + sizeof(struct coda_timestamp)); + ctx->frame_timestamps[decoded_idx].sequence = val; } - ctx->frame_timestamps[decoded_idx] = *ts; - kfree(ts); + mutex_unlock(&ctx->bitstream_mutex); val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; if (val == 0) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 0f8a2c970405..e84b32088fc0 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1116,12 +1116,14 @@ static void coda_stop_streaming(struct vb2_queue *q) if (!ctx->streamon_out && !ctx->streamon_cap) { struct coda_timestamp *ts; + mutex_lock(&ctx->bitstream_mutex); while (!list_empty(&ctx->timestamp_list)) { ts = list_first_entry(&ctx->timestamp_list, struct coda_timestamp, list); list_del(&ts->list); kfree(ts); } + mutex_unlock(&ctx->bitstream_mutex); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); ctx->runcounter = 0; -- GitLab From 2dc546d00c8deb22aac50c8cc0c6293aab975c6b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:18 -0300 Subject: [PATCH 0552/5088] [media] coda: fix coda_s_fmt_vid_out Set the context color space when s_fmt succeeded, not when it failed. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index e84b32088fc0..dfecb8602f07 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -504,7 +504,9 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, ret = coda_s_fmt(ctx, f); if (ret) - ctx->colorspace = f->fmt.pix.colorspace; + return ret; + + ctx->colorspace = f->fmt.pix.colorspace; return ret; } -- GitLab From f95a6ce16736ac3aca4eda2238ccdf1913f3567f Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:19 -0300 Subject: [PATCH 0553/5088] [media] coda: set capture frame size with output S_FMT This patch makes coda_s_fmt_vid_out propagate the output frame size to the capture side. The GStreamer v4l2videodec only ever calls S_FMT on the output side and then expects G_FMT on the capture side to return a valid format. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index dfecb8602f07..a1080a7728e6 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -496,6 +496,7 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); + struct v4l2_format f_cap; int ret; ret = coda_try_fmt_vid_out(file, priv, f); @@ -508,7 +509,16 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, ctx->colorspace = f->fmt.pix.colorspace; - return ret; + f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + coda_g_fmt(file, priv, &f_cap); + f_cap.fmt.pix.width = f->fmt.pix.width; + f_cap.fmt.pix.height = f->fmt.pix.height; + + ret = coda_try_fmt_vid_cap(file, priv, &f_cap); + if (ret) + return ret; + + return coda_s_fmt(ctx, &f_cap); } static int coda_qbuf(struct file *file, void *priv, -- GitLab From a188a668dda4ea6b9454066343b78d662946fe07 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 5 Aug 2014 14:00:20 -0300 Subject: [PATCH 0554/5088] [media] coda: disable old cropping ioctls Since we neither support composing on the OUTPUT side, nor cropping on the CAPTURE side, disable VIDIOC_CROPCAP and VIDIOC_G/S_CROP altogether. This silences a GStreamer warning when GStreamer tries to obtain the pixel aspect ratio using VIDIOC_CROPCAP. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index a1080a7728e6..ffb4c76e5755 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1661,6 +1661,11 @@ static int coda_register_device(struct coda_dev *dev, struct video_device *vfd) vfd->vfl_dir = VFL_DIR_M2M; video_set_drvdata(vfd, dev); + /* Not applicable, use the selection API instead */ + v4l2_disable_ioctl(vfd, VIDIOC_CROPCAP); + v4l2_disable_ioctl(vfd, VIDIOC_G_CROP); + v4l2_disable_ioctl(vfd, VIDIOC_S_CROP); + return video_register_device(vfd, VFL_TYPE_GRABBER, 0); } -- GitLab From f23797b636c4d69b29d2739ba5fc0e36b4e47390 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 6 Aug 2014 08:02:23 -0300 Subject: [PATCH 0555/5088] [media] coda: checkpatch cleanup This patch breaks most long lines, concatenates broken up text strings, and adds or removes parentheses where needed to make checkpatch happy. The long codec list lines and a few 81-wide lines remain. Signed-off-by: Philipp Zabel Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 143 ++++++++++++++-------- drivers/media/platform/coda/coda-common.c | 34 +++-- 2 files changed, 113 insertions(+), 64 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 18fa369d204d..07fc91aba1e0 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -37,7 +37,7 @@ static inline int coda_is_initialized(struct coda_dev *dev) { - return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0); + return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0; } static inline unsigned long coda_isbusy(struct coda_dev *dev) @@ -165,17 +165,20 @@ static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); } -static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf) +static int coda_bitstream_queue(struct coda_ctx *ctx, + struct vb2_buffer *src_buf) { u32 src_size = vb2_get_plane_payload(src_buf, 0); u32 n; - n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), src_size); + n = kfifo_in(&ctx->bitstream_fifo, vb2_plane_vaddr(src_buf, 0), + src_size); if (n < src_size) return -ENOSPC; - dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr, - ctx->bitstream.size, DMA_TO_DEVICE); + dma_sync_single_for_device(&ctx->dev->plat_dev->dev, + ctx->bitstream.paddr, ctx->bitstream.size, + DMA_TO_DEVICE); src_buf->v4l2_buf.sequence = ctx->qsequence++; @@ -246,11 +249,12 @@ void coda_bit_stream_end_flag(struct coda_ctx *ctx) ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + /* If this context is currently running, update the hardware flag */ if ((dev->devtype->product == CODA_960) && coda_isbusy(dev) && (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { - /* If this context is currently running, update the hardware flag */ - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + coda_write(dev, ctx->bit_stream_param, + CODA_REG_BIT_BIT_STREAM_PARAM); } } @@ -315,9 +319,10 @@ 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; - coda_parabuf_write(ctx, i * 3 + 0, paddr); /* Y */ - coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */ - coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* 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); /* mvcol buffer for h.264 */ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && @@ -374,18 +379,22 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx, /* worst case slice size */ size = (DIV_ROUND_UP(q_data->width, 16) * DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; - ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf"); + ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, + "slicebuf"); if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer", + v4l2_err(&dev->v4l2_dev, + "failed to allocate %d byte slice buffer", ctx->slicebuf.size); return ret; } } if (dev->devtype->product == CODA_7541) { - ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); + ret = coda_alloc_context_buf(ctx, &ctx->psbuf, + CODA7_PS_BUF_SIZE, "psbuf"); if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer"); + v4l2_err(&dev->v4l2_dev, + "failed to allocate psmem buffer"); goto err; } } @@ -396,7 +405,8 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx, size += CODA9_PS_SAVE_SIZE; ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf"); if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer", + v4l2_err(&dev->v4l2_dev, + "failed to allocate %d byte context buffer", ctx->workbuf.size); goto err; } @@ -465,6 +475,7 @@ static void coda_setup_iram(struct coda_ctx *ctx) { struct coda_iram_info *iram_info = &ctx->iram_info; struct coda_dev *dev = ctx->dev; + int w64, w128; int mb_width; int dbk_bits; int bit_bits; @@ -497,13 +508,15 @@ static void coda_setup_iram(struct coda_ctx *ctx) q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); mb_width = DIV_ROUND_UP(q_data_src->width, 16); + w128 = mb_width * 128; + w64 = mb_width * 64; /* Prioritize in case IRAM is too small for everything */ if (dev->devtype->product == CODA_7541) { iram_info->search_ram_size = round_up(mb_width * 16 * 36 + 2048, 1024); iram_info->search_ram_paddr = coda_iram_alloc(iram_info, - iram_info->search_ram_size); + iram_info->search_ram_size); if (!iram_info->search_ram_paddr) { pr_err("IRAM is smaller than the search ram size\n"); goto out; @@ -513,18 +526,18 @@ static void coda_setup_iram(struct coda_ctx *ctx) } /* Only H.264BP and H.263P3 are considered */ - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width); + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64); if (!iram_info->buf_dbk_c_use) goto out; iram_info->axi_sram_use |= dbk_bits; - iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); if (!iram_info->buf_bit_use) goto out; iram_info->axi_sram_use |= bit_bits; - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); if (!iram_info->buf_ip_ac_dc_use) goto out; iram_info->axi_sram_use |= ip_bits; @@ -535,19 +548,20 @@ static void coda_setup_iram(struct coda_ctx *ctx) q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); mb_width = DIV_ROUND_UP(q_data_dst->width, 16); + w128 = mb_width * 128; - iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width); - iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128); + iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128); if (!iram_info->buf_dbk_c_use) goto out; iram_info->axi_sram_use |= dbk_bits; - iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); if (!iram_info->buf_bit_use) goto out; iram_info->axi_sram_use |= bit_bits; - iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width); + iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); if (!iram_info->buf_ip_ac_dc_use) goto out; iram_info->axi_sram_use |= ip_bits; @@ -634,8 +648,8 @@ int coda_check_firmware(struct coda_dev *dev) clk_disable_unprepare(dev->clk_ahb); if (product != dev->devtype->product) { - v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s," - " Version: %u.%u.%u\n", + v4l2_err(&dev->v4l2_dev, + "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n", coda_product_name(dev->devtype->product), coda_product_name(product), major, minor, release); return -EINVAL; @@ -648,8 +662,9 @@ int coda_check_firmware(struct coda_dev *dev) v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", major, minor, release); } else { - v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: " - "%u.%u.%u\n", major, minor, release); + v4l2_warn(&dev->v4l2_dev, + "Unsupported firmware version: %u.%u.%u\n", + major, minor, release); } return 0; @@ -720,27 +735,32 @@ static int coda_start_encoding(struct coda_ctx *ctx) if (dev->devtype->product == CODA_DX6) { /* Configure the coda */ - coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); + coda_write(dev, dev->iram.paddr, + CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); } /* Could set rotation here if needed */ switch (dev->devtype->product) { case CODA_DX6: - value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET; - value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + value = (q_data_src->width & CODADX6_PICWIDTH_MASK) + << CODADX6_PICWIDTH_OFFSET; + value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) + << CODA_PICHEIGHT_OFFSET; break; case CODA_7541: if (dst_fourcc == V4L2_PIX_FMT_H264) { value = (round_up(q_data_src->width, 16) & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; value |= (round_up(q_data_src->height, 16) & - CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; break; } /* fallthrough */ case CODA_960: - value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; - value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + value = (q_data_src->width & CODA7_PICWIDTH_MASK) + << CODA7_PICWIDTH_OFFSET; + value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) + << CODA_PICHEIGHT_OFFSET; } coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); coda_write(dev, ctx->params.framerate, @@ -750,16 +770,20 @@ static int coda_start_encoding(struct coda_ctx *ctx) switch (dst_fourcc) { case V4L2_PIX_FMT_MPEG4: if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, CODA9_STD_MPEG4, + CODA_CMD_ENC_SEQ_COD_STD); else - coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, CODA_STD_MPEG4, + CODA_CMD_ENC_SEQ_COD_STD); coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); break; case V4L2_PIX_FMT_H264: if (dev->devtype->product == CODA_960) - coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, CODA9_STD_H264, + CODA_CMD_ENC_SEQ_COD_STD); else - coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, CODA_STD_H264, + CODA_CMD_ENC_SEQ_COD_STD); if (ctx->params.h264_deblk_enabled) { value = ((ctx->params.h264_deblk_alpha & CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << @@ -784,13 +808,17 @@ static int coda_start_encoding(struct coda_ctx *ctx) value = 0; break; case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: - value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; - value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) + << CODA_SLICING_SIZE_OFFSET; + value |= (1 & CODA_SLICING_UNIT_MASK) + << CODA_SLICING_UNIT_OFFSET; value |= 1 & CODA_SLICING_MODE_MASK; break; case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: - value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; - value |= (0 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) + << CODA_SLICING_SIZE_OFFSET; + value |= (0 & CODA_SLICING_UNIT_MASK) + << CODA_SLICING_UNIT_OFFSET; value |= 1 & CODA_SLICING_MODE_MASK; break; } @@ -800,7 +828,8 @@ static int coda_start_encoding(struct coda_ctx *ctx) if (ctx->params.bitrate) { /* Rate control enabled */ - value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; + value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) + << CODA_RATECONTROL_BITRATE_OFFSET; value |= 1 & CODA_RATECONTROL_ENABLE_MASK; if (dev->devtype->product == CODA_960) value |= BIT(31); /* disable autoskip */ @@ -919,8 +948,10 @@ static int coda_start_encoding(struct coda_ctx *ctx) CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); /* FIXME */ - coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); - coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B); + coda_write(dev, ctx->internal_frames[2].paddr, + CODA9_CMD_SET_FRAME_SUBSAMP_A); + coda_write(dev, ctx->internal_frames[3].paddr, + CODA9_CMD_SET_FRAME_SUBSAMP_B); } } @@ -1092,7 +1123,8 @@ static int coda_prepare_encode(struct coda_ctx *ctx) } /* submit */ - coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); + coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, + CODA_CMD_ENC_PIC_ROT_MODE); coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); @@ -1135,9 +1167,10 @@ static int coda_prepare_encode(struct coda_ctx *ctx) CODA_CMD_ENC_PIC_BB_SIZE); if (!ctx->streamon_out) { - /* After streamoff on the output side, set the stream end flag */ + /* After streamoff on the output side, set stream end flag */ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); + coda_write(dev, ctx->bit_stream_param, + CODA_REG_BIT_BIT_STREAM_PARAM); } if (dev->devtype->product != CODA_DX6) @@ -1217,7 +1250,8 @@ static void coda_seq_end_work(struct work_struct *work) mutex_lock(&dev->coda_mutex); v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__); + "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, + __func__); if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_END failed\n"); @@ -1550,7 +1584,8 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); break; case CODA_960: - coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */ + /* 'hardcode to use interrupt disable mode'? */ + coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); break; } @@ -1666,7 +1701,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) } } - ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); + ctx->frm_dis_flg = coda_read(dev, + CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); /* * The previous display frame was copied out by the rotator, @@ -1694,7 +1730,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) else if (ctx->display_idx < 0) ctx->hold = true; } else if (decoded_idx == -2) { - /* no frame was decoded, we still return the remaining buffers */ + /* no frame was decoded, we still return remaining buffers */ } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { v4l2_err(&dev->v4l2_dev, "decoded frame index out of range: %d\n", decoded_idx); @@ -1801,7 +1837,8 @@ irqreturn_t coda_irq_handler(int irq, void *data) ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); if (ctx == NULL) { - v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); + v4l2_err(&dev->v4l2_dev, + "Instance released before the end of transaction\n"); mutex_unlock(&dev->coda_mutex); return IRQ_HANDLED; } diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index ffb4c76e5755..0997b5c677bd 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -75,6 +75,7 @@ void coda_write(struct coda_dev *dev, u32 data, u32 reg) unsigned int coda_read(struct coda_dev *dev, u32 reg) { u32 data; + data = readl(dev->regs_base + reg); v4l2_dbg(2, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); @@ -736,7 +737,8 @@ static void coda_pic_run_work(struct work_struct *work) return; } - if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { + if (!wait_for_completion_timeout(&ctx->completion, + msecs_to_jiffies(1000))) { dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n"); ctx->hold = true; @@ -812,6 +814,7 @@ static void coda_lock(void *m2m_priv) { struct coda_ctx *ctx = m2m_priv; struct coda_dev *pcdev = ctx->dev; + mutex_lock(&pcdev->dev_mutex); } @@ -819,6 +822,7 @@ static void coda_unlock(void *m2m_priv) { struct coda_ctx *ctx = m2m_priv; struct coda_dev *pcdev = ctx->dev; + mutex_unlock(&pcdev->dev_mutex); } @@ -995,7 +999,8 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, if (name && parent) { buf->blob.data = buf->vaddr; buf->blob.size = size; - buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob); + buf->dentry = debugfs_create_blob(name, 0644, parent, + &buf->blob); if (!buf->dentry) dev_warn(&dev->plat_dev->dev, "failed to create debugfs entry %s\n", name); @@ -1276,17 +1281,20 @@ static int coda_ctrls_setup(struct coda_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, 500); + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, + 500); v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_HEADER_MODE, V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE), V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0); + V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, + 1920 * 1088 / 256, 1, 0); if (ctx->ctrls.error) { - v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)", + v4l2_err(&ctx->dev->v4l2_dev, + "control initialization error (%d)", ctx->ctrls.error); return -EINVAL; } @@ -1365,7 +1373,7 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, int ret; int idx; - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -1444,7 +1452,8 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev, ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL); if (!ctx->bitstream.vaddr) { - v4l2_err(&dev->v4l2_dev, "failed to allocate bitstream ringbuffer"); + v4l2_err(&dev->v4l2_dev, + "failed to allocate bitstream ringbuffer"); ret = -ENOMEM; goto err_dma_writecombine; } @@ -1617,10 +1626,12 @@ static int coda_hw_init(struct coda_dev *dev) /* Set default values */ switch (dev->devtype->product) { case CODA_DX6: - coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL); + coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, + CODA_REG_BIT_STREAM_CTRL); break; default: - coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL); + coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, + CODA_REG_BIT_STREAM_CTRL); } if (dev->devtype->product == CODA_960) coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL); @@ -1854,7 +1865,7 @@ static int coda_probe(struct platform_device *pdev) struct resource *res; int ret, irq; - dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) { dev_err(&pdev->dev, "Not enough memory for %s\n", CODA_NAME); @@ -1905,7 +1916,8 @@ static int coda_probe(struct platform_device *pdev) if (ret == -ENOENT || ret == -ENOSYS) { dev->rstc = NULL; } else { - dev_err(&pdev->dev, "failed get reset control: %d\n", ret); + dev_err(&pdev->dev, "failed get reset control: %d\n", + ret); return ret; } } -- GitLab From e47a81d8886d0262f9f6a4ecf7aa7e6ba2cb0dfc Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 11 Jun 2014 10:34:35 -0300 Subject: [PATCH 0556/5088] [media] smiapp: Use unlocked __v4l2_ctrl_modify_range() Instead of modifying the control ranges directly by manipulating struct v4l2_ctrl, use __v4l2_ctrl_modify_range() for the purpose. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 47 ++++++++------------------ 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 437ec29bdf64..bf8d3380111a 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -320,13 +320,7 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor) + sensor->vblank->val - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN]; - ctrl->maximum = max; - if (ctrl->default_value > max) - ctrl->default_value = max; - if (ctrl->val > max) - ctrl->val = max; - if (ctrl->cur.val > max) - ctrl->cur.val = max; + __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); } /* @@ -834,36 +828,25 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor) { struct v4l2_ctrl *vblank = sensor->vblank; struct v4l2_ctrl *hblank = sensor->hblank; + int min, max; - vblank->minimum = - max_t(int, - sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES], - sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] - - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); - vblank->maximum = - sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] - + min = max_t(int, + sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES], + sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] - + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); + max = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height; - vblank->val = clamp_t(int, vblank->val, - vblank->minimum, vblank->maximum); - vblank->default_value = vblank->minimum; - vblank->val = vblank->val; - vblank->cur.val = vblank->val; - - hblank->minimum = - max_t(int, - sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] - - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width, - sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]); - hblank->maximum = - sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] - + __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); + + min = max_t(int, + sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] - + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width, + sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]); + max = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width; - hblank->val = clamp_t(int, hblank->val, - hblank->minimum, hblank->maximum); - hblank->default_value = hblank->minimum; - hblank->val = hblank->val; - hblank->cur.val = hblank->val; + __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); __smiapp_update_exposure_limits(sensor); } -- GitLab From a328e7e3fd3030974b74da51daee625a14be0435 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 11 Jun 2014 10:37:36 -0300 Subject: [PATCH 0557/5088] [media] smiapp: Set 64-bit integer control using v4l2_ctrl_s_ctrl_int64() Don't manipulate struct v4l2_ctrl directly. Instead, use v4l2_ctrl_s_ctrl_int64() to change the values. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index bf8d3380111a..c4cc5de3ae59 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -298,8 +298,9 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor) if (rval < 0) return rval; - *sensor->pixel_rate_parray->p_cur.p_s64 = pll->vt_pix_clk_freq_hz; - *sensor->pixel_rate_csi->p_cur.p_s64 = pll->pixel_rate_csi; + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray, + pll->vt_pix_clk_freq_hz); + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi); return 0; } @@ -509,6 +510,10 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) return smiapp_write( sensor, SMIAPP_REG_U16_TEST_DATA_GREENB, ctrl->val); + case V4L2_CID_PIXEL_RATE: + /* For v4l2_ctrl_s_ctrl_int64() used internally. */ + return 0; + default: return -EINVAL; } -- GitLab From 29bbb7bd0a65e01a0423e1df764676119b71ecb3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 11 Aug 2014 18:09:32 -0300 Subject: [PATCH 0558/5088] [media] siano: add support for PCTV 77e Add support for PCTV microStick (77e) device that uses a sms1140 chipset. Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/sms-cards.c | 6 ++++++ drivers/media/common/siano/sms-cards.h | 1 + drivers/media/usb/siano/smsusb.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 82769993eeb7..82c7a1289f05 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -157,6 +157,12 @@ static struct sms_board sms_boards[] = { .type = SMS_DENVER_2160, .default_mode = DEVICE_MODE_DAB_TDMB, }, + [SMS1XXX_BOARD_PCTV_77E] = { + .name = "Hauppauge microStick 77e", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, + }, }; struct sms_board *sms_get_board(unsigned id) diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h index c63b544c49c5..4c4caddf9869 100644 --- a/drivers/media/common/siano/sms-cards.h +++ b/drivers/media/common/siano/sms-cards.h @@ -45,6 +45,7 @@ #define SMS1XXX_BOARD_SIANO_RIO 18 #define SMS1XXX_BOARD_SIANO_DENVER_1530 19 #define SMS1XXX_BOARD_SIANO_DENVER_2160 20 +#define SMS1XXX_BOARD_PCTV_77E 21 struct sms_board_gpio_cfg { int lna_vhf_exist; diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 1836a416d806..89c86ee2b225 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -655,6 +655,8 @@ static const struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD }, { USB_DEVICE(0x3275, 0x0080), .driver_info = SMS1XXX_BOARD_SIANO_RIO }, + { USB_DEVICE(0x2013, 0x0257), + .driver_info = SMS1XXX_BOARD_PCTV_77E }, { } /* Terminating entry */ }; -- GitLab From 2179de602c33d0b7b87f087dd7fbf35d22da4bd8 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 4 Aug 2014 08:13:16 -0300 Subject: [PATCH 0559/5088] [media] staging: media: as102: replace custom dprintk() with dev_dbg() remove dprintk() and replace it with dev_dbg() or pr_debug() in order to use the common kernel coding style. Signed-off-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/as102/as102_drv.c | 15 ++++---- drivers/staging/media/as102/as102_drv.h | 7 ---- drivers/staging/media/as102/as102_fe.c | 25 +++++-------- drivers/staging/media/as102/as102_usb_drv.c | 41 ++++++++++++--------- 4 files changed, 41 insertions(+), 47 deletions(-) diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c index 09d64cd67502..e0ee618e607a 100644 --- a/drivers/staging/media/as102/as102_drv.c +++ b/drivers/staging/media/as102/as102_drv.c @@ -31,10 +31,6 @@ #include "as102_fw.h" #include "dvbdev.h" -int as102_debug; -module_param_named(debug, as102_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)"); - int dual_tuner; module_param_named(dual_tuner, dual_tuner, int, 0644); MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)"); @@ -74,7 +70,8 @@ static void as102_stop_stream(struct as102_dev_t *dev) return; if (as10x_cmd_stop_streaming(bus_adap) < 0) - dprintk(debug, "as10x_cmd_stop_streaming failed\n"); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "as10x_cmd_stop_streaming failed\n"); mutex_unlock(&dev->bus_adap.lock); } @@ -112,14 +109,16 @@ static int as10x_pid_filter(struct as102_dev_t *dev, int ret = -EFAULT; if (mutex_lock_interruptible(&dev->bus_adap.lock)) { - dprintk(debug, "mutex_lock_interruptible(lock) failed !\n"); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "amutex_lock_interruptible(lock) failed !\n"); return -EBUSY; } switch (onoff) { case 0: ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); - dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", + dev_dbg(&dev->bus_adap.usb_dev->dev, + "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", index, pid, ret); break; case 1: @@ -131,7 +130,7 @@ static int as10x_pid_filter(struct as102_dev_t *dev, filter.pid = pid; ret = as10x_cmd_add_PID_filter(bus_adap, &filter); - dprintk(debug, + dev_dbg(&dev->bus_adap.usb_dev->dev, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", index, filter.idx, filter.pid, ret); break; diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h index a06837dcc05d..49d0c4259b00 100644 --- a/drivers/staging/media/as102/as102_drv.h +++ b/drivers/staging/media/as102/as102_drv.h @@ -27,17 +27,10 @@ #define DRIVER_FULL_NAME "Abilis Systems as10x usb driver" #define DRIVER_NAME "as10x_usb" -extern int as102_debug; #define debug as102_debug extern struct usb_driver as102_usb_driver; extern int elna_enable; -#define dprintk(debug, args...) \ - do { if (debug) { \ - pr_debug("%s: ", __func__); \ - printk(args); \ - } } while (0) - #define AS102_DEVICE_MAJOR 192 #define AS102_USB_BUF_SIZE 512 diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c index b686b7617cdc..67e55b84493f 100644 --- a/drivers/staging/media/as102/as102_fe.c +++ b/drivers/staging/media/as102/as102_fe.c @@ -46,7 +46,8 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe) /* send abilis command: SET_TUNE */ ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); if (ret != 0) - dprintk(debug, "as10x_cmd_set_tune failed. (err = %d)\n", ret); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "as10x_cmd_set_tune failed. (err = %d)\n", ret); mutex_unlock(&dev->bus_adap.lock); @@ -81,13 +82,6 @@ static int as102_fe_get_frontend(struct dvb_frontend *fe) static int as102_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *settings) { -#if 0 - dprintk(debug, "step_size = %d\n", settings->step_size); - dprintk(debug, "max_drift = %d\n", settings->max_drift); - dprintk(debug, "min_delay_ms = %d -> %d\n", settings->min_delay_ms, - 1000); -#endif - settings->min_delay_ms = 1000; return 0; @@ -110,7 +104,8 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) /* send abilis command: GET_TUNE_STATUS */ ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate); if (ret < 0) { - dprintk(debug, "as10x_cmd_get_tune_status failed (err = %d)\n", + dev_dbg(&dev->bus_adap.usb_dev->dev, + "as10x_cmd_get_tune_status failed (err = %d)\n", ret); goto out; } @@ -133,7 +128,8 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) *status = TUNE_STATUS_NOT_TUNED; } - dprintk(debug, "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", + dev_dbg(&dev->bus_adap.usb_dev->dev, + "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", tstate.tune_state, tstate.signal_strength, tstate.PER, tstate.BER); @@ -141,10 +137,10 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) if (as10x_cmd_get_demod_stats(&dev->bus_adap, (struct as10x_demod_stats *) &dev->demod_stats) < 0) { memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); - dprintk(debug, + dev_dbg(&dev->bus_adap.usb_dev->dev, "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); } else { - dprintk(debug, + dev_dbg(&dev->bus_adap.usb_dev->dev, "demod status: fc: 0x%08x, bad fc: 0x%08x, " "bytes corrected: 0x%08x , MER: 0x%04x\n", dev->demod_stats.frame_count, @@ -531,7 +527,7 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, break; } - dprintk(debug, "tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", + pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", params->frequency, tune_args->bandwidth, tune_args->guard_interval); @@ -556,8 +552,7 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, as102_fe_get_code_rate(params->code_rate_LP); } - dprintk(debug, - "\thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", + pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", tune_args->hierarchy, tune_args->hier_select == HIER_HIGH_PRIORITY ? "HP" : "LP", diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index e6f6278e97d6..86f83b9b1118 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -104,21 +104,22 @@ static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap, send_buf, send_buf_len, USB_CTRL_SET_TIMEOUT /* 200 */); if (ret < 0) { - dprintk(debug, "usb_control_msg(send) failed, err %i\n", - ret); + dev_dbg(&bus_adap->usb_dev->dev, + "usb_control_msg(send) failed, err %i\n", ret); return ret; } if (ret != send_buf_len) { - dprintk(debug, "only wrote %d of %d bytes\n", - ret, send_buf_len); + dev_dbg(&bus_adap->usb_dev->dev, + "only wrote %d of %d bytes\n", ret, send_buf_len); return -1; } } if (recv_buf != NULL) { #ifdef TRACE - dprintk(debug, "want to read: %d bytes\n", recv_buf_len); + dev_dbg(bus_adap->usb_dev->dev, + "want to read: %d bytes\n", recv_buf_len); #endif ret = usb_control_msg(bus_adap->usb_dev, usb_rcvctrlpipe(bus_adap->usb_dev, 0), @@ -130,12 +131,13 @@ static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap, recv_buf, recv_buf_len, USB_CTRL_GET_TIMEOUT /* 200 */); if (ret < 0) { - dprintk(debug, "usb_control_msg(recv) failed, err %i\n", - ret); + dev_dbg(&bus_adap->usb_dev->dev, + "usb_control_msg(recv) failed, err %i\n", ret); return ret; } #ifdef TRACE - dprintk(debug, "read %d bytes\n", recv_buf_len); + dev_dbg(bus_adap->usb_dev->dev, + "read %d bytes\n", recv_buf_len); #endif } @@ -153,13 +155,14 @@ static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap, usb_sndbulkpipe(bus_adap->usb_dev, 1), send_buf, send_buf_len, &actual_len, 200); if (ret) { - dprintk(debug, "usb_bulk_msg(send) failed, err %i\n", ret); + dev_dbg(&bus_adap->usb_dev->dev, + "usb_bulk_msg(send) failed, err %i\n", ret); return ret; } if (actual_len != send_buf_len) { - dprintk(debug, "only wrote %d of %d bytes\n", - actual_len, send_buf_len); + dev_dbg(&bus_adap->usb_dev->dev, "only wrote %d of %d bytes\n", + actual_len, send_buf_len); return -1; } return ret ? ret : actual_len; @@ -177,13 +180,14 @@ static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap, usb_rcvbulkpipe(bus_adap->usb_dev, 2), recv_buf, recv_buf_len, &actual_len, 200); if (ret) { - dprintk(debug, "usb_bulk_msg(recv) failed, err %i\n", ret); + dev_dbg(&bus_adap->usb_dev->dev, + "usb_bulk_msg(recv) failed, err %i\n", ret); return ret; } if (actual_len != recv_buf_len) { - dprintk(debug, "only read %d of %d bytes\n", - actual_len, recv_buf_len); + dev_dbg(&bus_adap->usb_dev->dev, "only read %d of %d bytes\n", + actual_len, recv_buf_len); return -1; } return ret ? ret : actual_len; @@ -211,7 +215,8 @@ static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) err = usb_submit_urb(urb, GFP_ATOMIC); if (err) - dprintk(debug, "%s: usb_submit_urb failed\n", __func__); + dev_dbg(&urb->dev->dev, + "%s: usb_submit_urb failed\n", __func__); return err; } @@ -256,7 +261,8 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) GFP_KERNEL, &dev->dma_addr); if (!dev->stream) { - dprintk(debug, "%s: usb_buffer_alloc failed\n", __func__); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "%s: usb_buffer_alloc failed\n", __func__); return -ENOMEM; } @@ -268,7 +274,8 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) urb = usb_alloc_urb(0, GFP_ATOMIC); if (urb == NULL) { - dprintk(debug, "%s: usb_alloc_urb failed\n", __func__); + dev_dbg(&dev->bus_adap.usb_dev->dev, + "%s: usb_alloc_urb failed\n", __func__); as102_free_usb_stream_buffer(dev); return -ENOMEM; } -- GitLab From d6317c68f3324e086799e12e4864231bb71829cb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:15 -0300 Subject: [PATCH 0560/5088] [media] as102: promote it out of staging This driver is stable and doesn't contain any really serious issue. Move it out of staging. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/Kconfig | 1 + drivers/media/usb/Makefile | 1 + drivers/{staging/media => media/usb}/as102/Kconfig | 0 drivers/{staging/media => media/usb}/as102/Makefile | 0 drivers/{staging/media => media/usb}/as102/as102_drv.c | 0 drivers/{staging/media => media/usb}/as102/as102_drv.h | 0 drivers/{staging/media => media/usb}/as102/as102_fe.c | 0 drivers/{staging/media => media/usb}/as102/as102_fw.c | 0 drivers/{staging/media => media/usb}/as102/as102_fw.h | 0 drivers/{staging/media => media/usb}/as102/as102_usb_drv.c | 0 drivers/{staging/media => media/usb}/as102/as102_usb_drv.h | 0 drivers/{staging/media => media/usb}/as102/as10x_cmd.c | 0 drivers/{staging/media => media/usb}/as102/as10x_cmd.h | 0 drivers/{staging/media => media/usb}/as102/as10x_cmd_cfg.c | 0 drivers/{staging/media => media/usb}/as102/as10x_cmd_stream.c | 0 drivers/{staging/media => media/usb}/as102/as10x_handle.h | 0 drivers/{staging/media => media/usb}/as102/as10x_types.h | 0 drivers/staging/media/Kconfig | 2 -- drivers/staging/media/Makefile | 1 - 19 files changed, 2 insertions(+), 3 deletions(-) rename drivers/{staging/media => media/usb}/as102/Kconfig (100%) rename drivers/{staging/media => media/usb}/as102/Makefile (100%) rename drivers/{staging/media => media/usb}/as102/as102_drv.c (100%) rename drivers/{staging/media => media/usb}/as102/as102_drv.h (100%) rename drivers/{staging/media => media/usb}/as102/as102_fe.c (100%) rename drivers/{staging/media => media/usb}/as102/as102_fw.c (100%) rename drivers/{staging/media => media/usb}/as102/as102_fw.h (100%) rename drivers/{staging/media => media/usb}/as102/as102_usb_drv.c (100%) rename drivers/{staging/media => media/usb}/as102/as102_usb_drv.h (100%) rename drivers/{staging/media => media/usb}/as102/as10x_cmd.c (100%) rename drivers/{staging/media => media/usb}/as102/as10x_cmd.h (100%) rename drivers/{staging/media => media/usb}/as102/as10x_cmd_cfg.c (100%) rename drivers/{staging/media => media/usb}/as102/as10x_cmd_stream.c (100%) rename drivers/{staging/media => media/usb}/as102/as10x_handle.h (100%) rename drivers/{staging/media => media/usb}/as102/as10x_types.h (100%) diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index 94d51e092db3..d6e8edc59b6d 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig @@ -46,6 +46,7 @@ source "drivers/media/usb/ttusb-budget/Kconfig" source "drivers/media/usb/ttusb-dec/Kconfig" source "drivers/media/usb/siano/Kconfig" source "drivers/media/usb/b2c2/Kconfig" +source "drivers/media/usb/as102/Kconfig" endif if (MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT) diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile index f438efffefc5..b5b645b91f4e 100644 --- a/drivers/media/usb/Makefile +++ b/drivers/media/usb/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_VIDEO_TM6000) += tm6000/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_USBTV) += usbtv/ obj-$(CONFIG_VIDEO_GO7007) += go7007/ +obj-$(CONFIG_DVB_AS102) += as102/ diff --git a/drivers/staging/media/as102/Kconfig b/drivers/media/usb/as102/Kconfig similarity index 100% rename from drivers/staging/media/as102/Kconfig rename to drivers/media/usb/as102/Kconfig diff --git a/drivers/staging/media/as102/Makefile b/drivers/media/usb/as102/Makefile similarity index 100% rename from drivers/staging/media/as102/Makefile rename to drivers/media/usb/as102/Makefile diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c similarity index 100% rename from drivers/staging/media/as102/as102_drv.c rename to drivers/media/usb/as102/as102_drv.c diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h similarity index 100% rename from drivers/staging/media/as102/as102_drv.h rename to drivers/media/usb/as102/as102_drv.h diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c similarity index 100% rename from drivers/staging/media/as102/as102_fe.c rename to drivers/media/usb/as102/as102_fe.c diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c similarity index 100% rename from drivers/staging/media/as102/as102_fw.c rename to drivers/media/usb/as102/as102_fw.c diff --git a/drivers/staging/media/as102/as102_fw.h b/drivers/media/usb/as102/as102_fw.h similarity index 100% rename from drivers/staging/media/as102/as102_fw.h rename to drivers/media/usb/as102/as102_fw.h diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c similarity index 100% rename from drivers/staging/media/as102/as102_usb_drv.c rename to drivers/media/usb/as102/as102_usb_drv.c diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/media/usb/as102/as102_usb_drv.h similarity index 100% rename from drivers/staging/media/as102/as102_usb_drv.h rename to drivers/media/usb/as102/as102_usb_drv.h diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/media/usb/as102/as10x_cmd.c similarity index 100% rename from drivers/staging/media/as102/as10x_cmd.c rename to drivers/media/usb/as102/as10x_cmd.c diff --git a/drivers/staging/media/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h similarity index 100% rename from drivers/staging/media/as102/as10x_cmd.h rename to drivers/media/usb/as102/as10x_cmd.h diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/media/usb/as102/as10x_cmd_cfg.c similarity index 100% rename from drivers/staging/media/as102/as10x_cmd_cfg.c rename to drivers/media/usb/as102/as10x_cmd_cfg.c diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/media/usb/as102/as10x_cmd_stream.c similarity index 100% rename from drivers/staging/media/as102/as10x_cmd_stream.c rename to drivers/media/usb/as102/as10x_cmd_stream.c diff --git a/drivers/staging/media/as102/as10x_handle.h b/drivers/media/usb/as102/as10x_handle.h similarity index 100% rename from drivers/staging/media/as102/as10x_handle.h rename to drivers/media/usb/as102/as10x_handle.h diff --git a/drivers/staging/media/as102/as10x_types.h b/drivers/media/usb/as102/as10x_types.h similarity index 100% rename from drivers/staging/media/as102/as10x_types.h rename to drivers/media/usb/as102/as10x_types.h diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 3323eb5e77b0..655cf5037b0b 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -19,8 +19,6 @@ menuconfig STAGING_MEDIA if STAGING_MEDIA # Please keep them in alphabetic order -source "drivers/staging/media/as102/Kconfig" - source "drivers/staging/media/bcm2048/Kconfig" source "drivers/staging/media/cxd2099/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 7db83f373f63..6dbe578178cd 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,4 +1,3 @@ -obj-$(CONFIG_DVB_AS102) += as102/ obj-$(CONFIG_I2C_BCM2048) += bcm2048/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_LIRC_STAGING) += lirc/ -- GitLab From 1f2563d68cce0d45b81a47894c135f65f192b1a9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:16 -0300 Subject: [PATCH 0561/5088] [media] as102: get rid of FSF mail address Make checkpatch happier by removing FSF mail address. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_drv.c | 4 ---- drivers/media/usb/as102/as102_drv.h | 4 ---- drivers/media/usb/as102/as102_fe.c | 4 ---- drivers/media/usb/as102/as102_fw.c | 4 ---- drivers/media/usb/as102/as102_fw.h | 4 ---- drivers/media/usb/as102/as102_usb_drv.c | 4 ---- drivers/media/usb/as102/as102_usb_drv.h | 4 ---- drivers/media/usb/as102/as10x_cmd.c | 4 ---- drivers/media/usb/as102/as10x_cmd.h | 4 ---- drivers/media/usb/as102/as10x_cmd_cfg.c | 4 ---- drivers/media/usb/as102/as10x_cmd_stream.c | 4 ---- drivers/media/usb/as102/as10x_handle.h | 4 ---- drivers/media/usb/as102/as10x_types.h | 4 ---- 13 files changed, 52 deletions(-) diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c index e0ee618e607a..d90a6651f03e 100644 --- a/drivers/media/usb/as102/as102_drv.c +++ b/drivers/media/usb/as102/as102_drv.c @@ -12,10 +12,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 #include diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h index 49d0c4259b00..d6e08e23b366 100644 --- a/drivers/media/usb/as102/as102_drv.h +++ b/drivers/media/usb/as102/as102_drv.h @@ -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/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 67e55b84493f..29a6d38f91a9 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -12,10 +12,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 "as102_drv.h" #include "as10x_types.h" diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c index f33f752c0aad..07d08c49f4d4 100644 --- a/drivers/media/usb/as102/as102_fw.c +++ b/drivers/media/usb/as102/as102_fw.c @@ -12,10 +12,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 #include diff --git a/drivers/media/usb/as102/as102_fw.h b/drivers/media/usb/as102/as102_fw.h index 4bfc6849d95a..2732b784216d 100644 --- a/drivers/media/usb/as102/as102_fw.h +++ b/drivers/media/usb/as102/as102_fw.h @@ -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. */ #define MAX_FW_PKT_SIZE 64 diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c index 86f83b9b1118..43133df771ff 100644 --- a/drivers/media/usb/as102/as102_usb_drv.c +++ b/drivers/media/usb/as102/as102_usb_drv.c @@ -12,10 +12,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 #include diff --git a/drivers/media/usb/as102/as102_usb_drv.h b/drivers/media/usb/as102/as102_usb_drv.h index 1ad1ec52b11e..4fb1baa8cac0 100644 --- a/drivers/media/usb/as102/as102_usb_drv.h +++ b/drivers/media/usb/as102/as102_usb_drv.h @@ -12,10 +12,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. */ #ifndef _AS102_USB_DRV_H_ #define _AS102_USB_DRV_H_ diff --git a/drivers/media/usb/as102/as10x_cmd.c b/drivers/media/usb/as102/as10x_cmd.c index 9e49f15a7c9f..8868c52500ee 100644 --- a/drivers/media/usb/as102/as10x_cmd.c +++ b/drivers/media/usb/as102/as10x_cmd.c @@ -12,10 +12,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/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h index e21ec6c702a9..1c9ea2c2175e 100644 --- a/drivers/media/usb/as102/as10x_cmd.h +++ b/drivers/media/usb/as102/as10x_cmd.h @@ -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. */ #ifndef _AS10X_CMD_H_ #define _AS10X_CMD_H_ diff --git a/drivers/media/usb/as102/as10x_cmd_cfg.c b/drivers/media/usb/as102/as10x_cmd_cfg.c index b1e300d88753..833463343ada 100644 --- a/drivers/media/usb/as102/as10x_cmd_cfg.c +++ b/drivers/media/usb/as102/as10x_cmd_cfg.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/media/usb/as102/as10x_cmd_stream.c b/drivers/media/usb/as102/as10x_cmd_stream.c index 1088ca1fe92f..126aea976639 100644 --- a/drivers/media/usb/as102/as10x_cmd_stream.c +++ b/drivers/media/usb/as102/as10x_cmd_stream.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/media/usb/as102/as10x_handle.h b/drivers/media/usb/as102/as10x_handle.h index 5638b191b780..e535fffbcd94 100644 --- a/drivers/media/usb/as102/as10x_handle.h +++ b/drivers/media/usb/as102/as10x_handle.h @@ -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. */ #ifdef __KERNEL__ struct as10x_bus_adapter_t; diff --git a/drivers/media/usb/as102/as10x_types.h b/drivers/media/usb/as102/as10x_types.h index af26e057d9a2..f82d51e542e3 100644 --- a/drivers/media/usb/as102/as10x_types.h +++ b/drivers/media/usb/as102/as10x_types.h @@ -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. */ #ifndef _AS10X_TYPES_H_ #define _AS10X_TYPES_H_ -- GitLab From 1d5c2bb1f9ded9af7bb7e4d2b9beeacbfdbc6f2b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:17 -0300 Subject: [PATCH 0562/5088] [media] as102: CodingStyle fixes Fix this warning: WARNING: quoted string split across lines 566: FILE: drivers/media/usb/as102/as102_fe.c:141: + "demod status: fc: 0x%08x, bad fc: 0x%08x, " + "bytes corrected: 0x%08x , MER: 0x%04x\n", Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_fe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 29a6d38f91a9..9596756b3869 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -137,8 +137,7 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); } else { dev_dbg(&dev->bus_adap.usb_dev->dev, - "demod status: fc: 0x%08x, bad fc: 0x%08x, " - "bytes corrected: 0x%08x , MER: 0x%04x\n", + "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n", dev->demod_stats.frame_count, dev->demod_stats.bad_frame_count, dev->demod_stats.bytes_fixed_by_rs, -- GitLab From d8eb070b6649c1663204300555fb740affc6cdc2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:18 -0300 Subject: [PATCH 0563/5088] [media] as102: better name the unknown frontend Make the frontend .name more coherent with DVB namespace. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_fe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 9596756b3869..041bb80aa4ba 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -245,7 +245,7 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) static struct dvb_frontend_ops as102_fe_ops = { .delsys = { SYS_DVBT }, .info = { - .name = "Unknown AS102 device", + .name = "Abilis AS102 DVB-T", .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, -- GitLab From b601d9a5d668119219d1db95cbe04fdc38eaf5a4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:19 -0300 Subject: [PATCH 0564/5088] [media] as102: Move ancillary routines to the beggining Avoid having function prototypes by moving some ancillary routines to the beginning of the file. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_drv.c | 17 +- drivers/media/usb/as102/as102_drv.h | 15 +- drivers/media/usb/as102/as102_fe.c | 542 +++++++++++++--------------- 3 files changed, 274 insertions(+), 300 deletions(-) diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c index d90a6651f03e..ff5bd2e5657a 100644 --- a/drivers/media/usb/as102/as102_drv.c +++ b/drivers/media/usb/as102/as102_drv.c @@ -216,7 +216,17 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) goto edmxdinit; } - ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe); + /* Attach the frontend */ + as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name, + &as102_dev->bus_adap, + as102_dev->elna_cfg); + if (!as102_dev->dvb_fe) { + dev_err(dev, "%s: as102_attach() failed: %d", + __func__, ret); + goto efereg; + } + + ret = dvb_register_frontend(&as102_dev->dvb_adap, as102_dev->dvb_fe); if (ret < 0) { dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d", __func__, ret); @@ -252,7 +262,10 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) void as102_dvb_unregister(struct as102_dev_t *as102_dev) { /* unregister as102 frontend */ - as102_dvb_unregister_fe(&as102_dev->dvb_fe); + dvb_unregister_frontend(as102_dev->dvb_fe); + + /* detach frontend */ + dvb_frontend_detach(as102_dev->dvb_fe); /* unregister demux device */ dvb_dmxdev_release(&as102_dev->dvb_dmxdev); diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h index d6e08e23b366..1e2a76d3c517 100644 --- a/drivers/media/usb/as102/as102_drv.h +++ b/drivers/media/usb/as102/as102_drv.h @@ -60,17 +60,10 @@ struct as102_dev_t { uint8_t elna_cfg; struct dvb_adapter dvb_adap; - struct dvb_frontend dvb_fe; + struct dvb_frontend *dvb_fe; struct dvb_demux dvb_dmx; struct dmxdev dvb_dmxdev; - /* demodulator stats */ - struct as10x_demod_stats demod_stats; - /* signal strength */ - uint16_t signal_strength; - /* bit error rate */ - uint32_t ber; - /* timer handle to trig ts stream download */ struct timer_list timer_handle; @@ -84,5 +77,7 @@ struct as102_dev_t { int as102_dvb_register(struct as102_dev_t *dev); void as102_dvb_unregister(struct as102_dev_t *dev); -int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe); -int as102_dvb_unregister_fe(struct dvb_frontend *dev); +/* FIXME: move it to a separate header */ +struct dvb_frontend *as102_attach(const char *name, + struct as10x_bus_adapter_t *bus_adap, + uint8_t elna_cfg); diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 041bb80aa4ba..7ec1c67ba119 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -17,298 +17,19 @@ #include "as10x_types.h" #include "as10x_cmd.h" -static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *dst, - struct as10x_tps *src); +struct as102_state { + struct dvb_frontend frontend; + struct as10x_demod_stats demod_stats; + struct as10x_bus_adapter_t *bus_adap; -static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst, - struct dtv_frontend_properties *src); + uint8_t elna_cfg; -static int as102_fe_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - int ret = 0; - struct as102_dev_t *dev; - struct as10x_tune_args tune_args = { 0 }; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - as102_fe_copy_tune_parameters(&tune_args, p); - - /* send abilis command: SET_TUNE */ - ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); - if (ret != 0) - dev_dbg(&dev->bus_adap.usb_dev->dev, - "as10x_cmd_set_tune failed. (err = %d)\n", ret); - - mutex_unlock(&dev->bus_adap.lock); - - return (ret < 0) ? -EINVAL : 0; -} - -static int as102_fe_get_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - int ret = 0; - struct as102_dev_t *dev; - struct as10x_tps tps = { 0 }; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -EINVAL; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - /* send abilis command: GET_TPS */ - ret = as10x_cmd_get_tps(&dev->bus_adap, &tps); - - if (ret == 0) - as10x_fe_copy_tps_parameters(p, &tps); - - mutex_unlock(&dev->bus_adap.lock); - - return (ret < 0) ? -EINVAL : 0; -} - -static int as102_fe_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *settings) { - - settings->min_delay_ms = 1000; - - return 0; -} - - -static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - int ret = 0; - struct as102_dev_t *dev; - struct as10x_tune_status tstate = { 0 }; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - /* send abilis command: GET_TUNE_STATUS */ - ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate); - if (ret < 0) { - dev_dbg(&dev->bus_adap.usb_dev->dev, - "as10x_cmd_get_tune_status failed (err = %d)\n", - ret); - goto out; - } - - dev->signal_strength = tstate.signal_strength; - dev->ber = tstate.BER; - - switch (tstate.tune_state) { - case TUNE_STATUS_SIGNAL_DVB_OK: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - break; - case TUNE_STATUS_STREAM_DETECTED: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; - break; - case TUNE_STATUS_STREAM_TUNED: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | - FE_HAS_LOCK; - break; - default: - *status = TUNE_STATUS_NOT_TUNED; - } - - dev_dbg(&dev->bus_adap.usb_dev->dev, - "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", - tstate.tune_state, tstate.signal_strength, - tstate.PER, tstate.BER); - - if (*status & FE_HAS_LOCK) { - if (as10x_cmd_get_demod_stats(&dev->bus_adap, - (struct as10x_demod_stats *) &dev->demod_stats) < 0) { - memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); - dev_dbg(&dev->bus_adap.usb_dev->dev, - "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); - } else { - dev_dbg(&dev->bus_adap.usb_dev->dev, - "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n", - dev->demod_stats.frame_count, - dev->demod_stats.bad_frame_count, - dev->demod_stats.bytes_fixed_by_rs, - dev->demod_stats.mer); - } - } else { - memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); - } - -out: - mutex_unlock(&dev->bus_adap.lock); - return ret; -} - -/* - * Note: - * - in AS102 SNR=MER - * - the SNR will be returned in linear terms, i.e. not in dB - * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB - * - the accuracy is >2dB for SNR values outside this range - */ -static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - *snr = dev->demod_stats.mer; - - return 0; -} - -static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - *ber = dev->ber; - - return 0; -} - -static int as102_fe_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2); - - return 0; -} - -static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - struct as102_dev_t *dev; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (dev->demod_stats.has_started) - *ucblocks = dev->demod_stats.bad_frame_count; - else - *ucblocks = 0; - - return 0; -} - -static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct as102_dev_t *dev; - int ret; - - dev = (struct as102_dev_t *) fe->tuner_priv; - if (dev == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&dev->bus_adap.lock)) - return -EBUSY; - - if (acquire) { - if (elna_enable) - as10x_cmd_set_context(&dev->bus_adap, - CONTEXT_LNA, dev->elna_cfg); - - ret = as10x_cmd_turn_on(&dev->bus_adap); - } else { - ret = as10x_cmd_turn_off(&dev->bus_adap); - } - - mutex_unlock(&dev->bus_adap.lock); - - return ret; -} - -static struct dvb_frontend_ops as102_fe_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "Abilis AS102 DVB-T", - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, - .caps = FE_CAN_INVERSION_AUTO - | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 - | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO - | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK - | FE_CAN_QAM_AUTO - | FE_CAN_TRANSMISSION_MODE_AUTO - | FE_CAN_GUARD_INTERVAL_AUTO - | FE_CAN_HIERARCHY_AUTO - | FE_CAN_RECOVER - | FE_CAN_MUTE_TS - }, - - .set_frontend = as102_fe_set_frontend, - .get_frontend = as102_fe_get_frontend, - .get_tune_settings = as102_fe_get_tune_settings, - - .read_status = as102_fe_read_status, - .read_snr = as102_fe_read_snr, - .read_ber = as102_fe_read_ber, - .read_signal_strength = as102_fe_read_signal_strength, - .read_ucblocks = as102_fe_read_ucblocks, - .ts_bus_ctrl = as102_fe_ts_bus_ctrl, + /* signal strength */ + uint16_t signal_strength; + /* bit error rate */ + uint32_t ber; }; -int as102_dvb_unregister_fe(struct dvb_frontend *fe) -{ - /* unregister frontend */ - dvb_unregister_frontend(fe); - - /* detach frontend */ - dvb_frontend_detach(fe); - - return 0; -} - -int as102_dvb_register_fe(struct as102_dev_t *as102_dev, - struct dvb_frontend *dvb_fe) -{ - int errno; - struct dvb_adapter *dvb_adap; - - if (as102_dev == NULL) - return -EINVAL; - - /* extract dvb_adapter */ - dvb_adap = &as102_dev->dvb_adap; - - /* init frontend callback ops */ - memcpy(&dvb_fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); - strncpy(dvb_fe->ops.info.name, as102_dev->name, - sizeof(dvb_fe->ops.info.name)); - - /* register dvb frontend */ - errno = dvb_register_frontend(dvb_adap, dvb_fe); - if (errno == 0) - dvb_fe->tuner_priv = as102_dev; - - return errno; -} - static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps, struct as10x_tps *as10x_tps) { @@ -559,3 +280,248 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, as102_fe_get_code_rate(params->code_rate_HP); } } + +static int as102_fe_set_frontend(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int ret = 0; + struct as10x_tune_args tune_args = { 0 }; + + if (mutex_lock_interruptible(&state->bus_adap->lock)) + return -EBUSY; + + as102_fe_copy_tune_parameters(&tune_args, p); + + /* send abilis command: SET_TUNE */ + ret = as10x_cmd_set_tune(state->bus_adap, &tune_args); + if (ret != 0) + dev_dbg(&state->bus_adap->usb_dev->dev, + "as10x_cmd_set_tune failed. (err = %d)\n", ret); + + mutex_unlock(&state->bus_adap->lock); + + return (ret < 0) ? -EINVAL : 0; +} + +static int as102_fe_get_frontend(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int ret = 0; + struct as10x_tps tps = { 0 }; + + if (mutex_lock_interruptible(&state->bus_adap->lock)) + return -EBUSY; + + /* send abilis command: GET_TPS */ + ret = as10x_cmd_get_tps(state->bus_adap, &tps); + + if (ret == 0) + as10x_fe_copy_tps_parameters(p, &tps); + + mutex_unlock(&state->bus_adap->lock); + + return (ret < 0) ? -EINVAL : 0; +} + +static int as102_fe_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *settings) { + + settings->min_delay_ms = 1000; + + return 0; +} + + +static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + int ret = 0; + struct as102_state *state = fe->demodulator_priv; + struct as10x_tune_status tstate = { 0 }; + + if (mutex_lock_interruptible(&state->bus_adap->lock)) + return -EBUSY; + + /* send abilis command: GET_TUNE_STATUS */ + ret = as10x_cmd_get_tune_status(state->bus_adap, &tstate); + if (ret < 0) { + dev_dbg(&state->bus_adap->usb_dev->dev, + "as10x_cmd_get_tune_status failed (err = %d)\n", + ret); + goto out; + } + + state->signal_strength = tstate.signal_strength; + state->ber = tstate.BER; + + switch (tstate.tune_state) { + case TUNE_STATUS_SIGNAL_DVB_OK: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + break; + case TUNE_STATUS_STREAM_DETECTED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; + break; + case TUNE_STATUS_STREAM_TUNED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | + FE_HAS_LOCK; + break; + default: + *status = TUNE_STATUS_NOT_TUNED; + } + + dev_dbg(&state->bus_adap->usb_dev->dev, + "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", + tstate.tune_state, tstate.signal_strength, + tstate.PER, tstate.BER); + + if (*status & FE_HAS_LOCK) { + if (as10x_cmd_get_demod_stats(state->bus_adap, + (struct as10x_demod_stats *) &state->demod_stats) < 0) { + memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + dev_dbg(&state->bus_adap->usb_dev->dev, + "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); + } else { + dev_dbg(&state->bus_adap->usb_dev->dev, + "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n", + state->demod_stats.frame_count, + state->demod_stats.bad_frame_count, + state->demod_stats.bytes_fixed_by_rs, + state->demod_stats.mer); + } + } else { + memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + } + +out: + mutex_unlock(&state->bus_adap->lock); + return ret; +} + +/* + * Note: + * - in AS102 SNR=MER + * - the SNR will be returned in linear terms, i.e. not in dB + * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB + * - the accuracy is >2dB for SNR values outside this range + */ +static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct as102_state *state = fe->demodulator_priv; + + *snr = state->demod_stats.mer; + + return 0; +} + +static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct as102_state *state = fe->demodulator_priv; + + *ber = state->ber; + + return 0; +} + +static int as102_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct as102_state *state = fe->demodulator_priv; + + *strength = (((0xffff * 400) * state->signal_strength + 41000) * 2); + + return 0; +} + +static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct as102_state *state = fe->demodulator_priv; + + if (state->demod_stats.has_started) + *ucblocks = state->demod_stats.bad_frame_count; + else + *ucblocks = 0; + + return 0; +} + +static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct as102_state *state = fe->demodulator_priv; + int ret; + + if (mutex_lock_interruptible(&state->bus_adap->lock)) + return -EBUSY; + + if (acquire) { + if (elna_enable) + as10x_cmd_set_context(state->bus_adap, + CONTEXT_LNA, state->elna_cfg); + + ret = as10x_cmd_turn_on(state->bus_adap); + } else { + ret = as10x_cmd_turn_off(state->bus_adap); + } + + mutex_unlock(&state->bus_adap->lock); + + return ret; +} + +static struct dvb_frontend_ops as102_fe_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Abilis AS102 DVB-T", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_INVERSION_AUTO + | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 + | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO + | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK + | FE_CAN_QAM_AUTO + | FE_CAN_TRANSMISSION_MODE_AUTO + | FE_CAN_GUARD_INTERVAL_AUTO + | FE_CAN_HIERARCHY_AUTO + | FE_CAN_RECOVER + | FE_CAN_MUTE_TS + }, + + .set_frontend = as102_fe_set_frontend, + .get_frontend = as102_fe_get_frontend, + .get_tune_settings = as102_fe_get_tune_settings, + + .read_status = as102_fe_read_status, + .read_snr = as102_fe_read_snr, + .read_ber = as102_fe_read_ber, + .read_signal_strength = as102_fe_read_signal_strength, + .read_ucblocks = as102_fe_read_ucblocks, + .ts_bus_ctrl = as102_fe_ts_bus_ctrl, +}; + +struct dvb_frontend *as102_attach(const char *name, + struct as10x_bus_adapter_t *bus_adap, + uint8_t elna_cfg) +{ + struct as102_state *state; + struct dvb_frontend *fe; + + state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); + if (state == NULL) { + dev_err(&bus_adap->usb_dev->dev, + "%s: unable to allocate memory for state\n", __func__); + return NULL; + } + fe = &state->frontend; + fe->demodulator_priv = state; + state->bus_adap = bus_adap; + state->elna_cfg = elna_cfg; + + /* init frontend callback ops */ + memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); + strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name)); + + return fe; + +} +EXPORT_SYMBOL_GPL(as102_attach); -- GitLab From 1d6207fd2c262deb7006c9269eec33e64c5e514f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:20 -0300 Subject: [PATCH 0565/5088] [media] as102: get rid of as102_fe_copy_tune_parameters() This function just parses the frontend cache and converts to the as102 internal format message. Get rid of it. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_fe.c | 117 ++++++++++++++--------------- 1 file changed, 55 insertions(+), 62 deletions(-) diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 7ec1c67ba119..975ad638ee41 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -156,144 +156,137 @@ static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) return c; } -static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, - struct dtv_frontend_properties *params) +static int as102_fe_set_frontend(struct dvb_frontend *fe) { + struct as102_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret = 0; + struct as10x_tune_args tune_args = { 0 }; /* set frequency */ - tune_args->freq = params->frequency / 1000; + tune_args.freq = c->frequency / 1000; /* fix interleaving_mode */ - tune_args->interleaving_mode = INTLV_NATIVE; + tune_args.interleaving_mode = INTLV_NATIVE; - switch (params->bandwidth_hz) { + switch (c->bandwidth_hz) { case 8000000: - tune_args->bandwidth = BW_8_MHZ; + tune_args.bandwidth = BW_8_MHZ; break; case 7000000: - tune_args->bandwidth = BW_7_MHZ; + tune_args.bandwidth = BW_7_MHZ; break; case 6000000: - tune_args->bandwidth = BW_6_MHZ; + tune_args.bandwidth = BW_6_MHZ; break; default: - tune_args->bandwidth = BW_8_MHZ; + tune_args.bandwidth = BW_8_MHZ; } - switch (params->guard_interval) { + switch (c->guard_interval) { case GUARD_INTERVAL_1_32: - tune_args->guard_interval = GUARD_INT_1_32; + tune_args.guard_interval = GUARD_INT_1_32; break; case GUARD_INTERVAL_1_16: - tune_args->guard_interval = GUARD_INT_1_16; + tune_args.guard_interval = GUARD_INT_1_16; break; case GUARD_INTERVAL_1_8: - tune_args->guard_interval = GUARD_INT_1_8; + tune_args.guard_interval = GUARD_INT_1_8; break; case GUARD_INTERVAL_1_4: - tune_args->guard_interval = GUARD_INT_1_4; + tune_args.guard_interval = GUARD_INT_1_4; break; case GUARD_INTERVAL_AUTO: default: - tune_args->guard_interval = GUARD_UNKNOWN; + tune_args.guard_interval = GUARD_UNKNOWN; break; } - switch (params->modulation) { + switch (c->modulation) { case QPSK: - tune_args->modulation = CONST_QPSK; + tune_args.modulation = CONST_QPSK; break; case QAM_16: - tune_args->modulation = CONST_QAM16; + tune_args.modulation = CONST_QAM16; break; case QAM_64: - tune_args->modulation = CONST_QAM64; + tune_args.modulation = CONST_QAM64; break; default: - tune_args->modulation = CONST_UNKNOWN; + tune_args.modulation = CONST_UNKNOWN; break; } - switch (params->transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_2K: - tune_args->transmission_mode = TRANS_MODE_2K; + tune_args.transmission_mode = TRANS_MODE_2K; break; case TRANSMISSION_MODE_8K: - tune_args->transmission_mode = TRANS_MODE_8K; + tune_args.transmission_mode = TRANS_MODE_8K; break; default: - tune_args->transmission_mode = TRANS_MODE_UNKNOWN; + tune_args.transmission_mode = TRANS_MODE_UNKNOWN; } - switch (params->hierarchy) { + switch (c->hierarchy) { case HIERARCHY_NONE: - tune_args->hierarchy = HIER_NONE; + tune_args.hierarchy = HIER_NONE; break; case HIERARCHY_1: - tune_args->hierarchy = HIER_ALPHA_1; + tune_args.hierarchy = HIER_ALPHA_1; break; case HIERARCHY_2: - tune_args->hierarchy = HIER_ALPHA_2; + tune_args.hierarchy = HIER_ALPHA_2; break; case HIERARCHY_4: - tune_args->hierarchy = HIER_ALPHA_4; + tune_args.hierarchy = HIER_ALPHA_4; break; case HIERARCHY_AUTO: - tune_args->hierarchy = HIER_UNKNOWN; + tune_args.hierarchy = HIER_UNKNOWN; break; } pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", - params->frequency, - tune_args->bandwidth, - tune_args->guard_interval); + c->frequency, + tune_args.bandwidth, + tune_args.guard_interval); /* * Detect a hierarchy selection * if HP/LP are both set to FEC_NONE, HP will be selected. */ - if ((tune_args->hierarchy != HIER_NONE) && - ((params->code_rate_LP == FEC_NONE) || - (params->code_rate_HP == FEC_NONE))) { - - if (params->code_rate_LP == FEC_NONE) { - tune_args->hier_select = HIER_HIGH_PRIORITY; - tune_args->code_rate = - as102_fe_get_code_rate(params->code_rate_HP); + if ((tune_args.hierarchy != HIER_NONE) && + ((c->code_rate_LP == FEC_NONE) || + (c->code_rate_HP == FEC_NONE))) { + + if (c->code_rate_LP == FEC_NONE) { + tune_args.hier_select = HIER_HIGH_PRIORITY; + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_HP); } - if (params->code_rate_HP == FEC_NONE) { - tune_args->hier_select = HIER_LOW_PRIORITY; - tune_args->code_rate = - as102_fe_get_code_rate(params->code_rate_LP); + if (c->code_rate_HP == FEC_NONE) { + tune_args.hier_select = HIER_LOW_PRIORITY; + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_LP); } pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", - tune_args->hierarchy, - tune_args->hier_select == HIER_HIGH_PRIORITY ? + tune_args.hierarchy, + tune_args.hier_select == HIER_HIGH_PRIORITY ? "HP" : "LP", - tune_args->hier_select == HIER_HIGH_PRIORITY ? + tune_args.hier_select == HIER_HIGH_PRIORITY ? "HP" : "LP", - tune_args->code_rate); + tune_args.code_rate); } else { - tune_args->code_rate = - as102_fe_get_code_rate(params->code_rate_HP); + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_HP); } -} - -static int as102_fe_set_frontend(struct dvb_frontend *fe) -{ - struct as102_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - int ret = 0; - struct as10x_tune_args tune_args = { 0 }; + /* Set frontend arguments */ if (mutex_lock_interruptible(&state->bus_adap->lock)) return -EBUSY; - as102_fe_copy_tune_parameters(&tune_args, p); - - /* send abilis command: SET_TUNE */ ret = as10x_cmd_set_tune(state->bus_adap, &tune_args); if (ret != 0) dev_dbg(&state->bus_adap->usb_dev->dev, -- GitLab From c098c219b0c2da64250dd0542c5c54ca7245d1a5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:21 -0300 Subject: [PATCH 0566/5088] [media] as102: get rid of as10x_fe_copy_tps_parameters() This function just converts from the as10x internal data into the DVBv5 cache. Get rid of it. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_fe.c | 201 ++++++++++++++--------------- 1 file changed, 98 insertions(+), 103 deletions(-) diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 975ad638ee41..0cd19f23eca9 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -30,104 +30,6 @@ struct as102_state { uint32_t ber; }; -static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps, - struct as10x_tps *as10x_tps) -{ - - /* extract constellation */ - switch (as10x_tps->modulation) { - case CONST_QPSK: - fe_tps->modulation = QPSK; - break; - case CONST_QAM16: - fe_tps->modulation = QAM_16; - break; - case CONST_QAM64: - fe_tps->modulation = QAM_64; - break; - } - - /* extract hierarchy */ - switch (as10x_tps->hierarchy) { - case HIER_NONE: - fe_tps->hierarchy = HIERARCHY_NONE; - break; - case HIER_ALPHA_1: - fe_tps->hierarchy = HIERARCHY_1; - break; - case HIER_ALPHA_2: - fe_tps->hierarchy = HIERARCHY_2; - break; - case HIER_ALPHA_4: - fe_tps->hierarchy = HIERARCHY_4; - break; - } - - /* extract code rate HP */ - switch (as10x_tps->code_rate_HP) { - case CODE_RATE_1_2: - fe_tps->code_rate_HP = FEC_1_2; - break; - case CODE_RATE_2_3: - fe_tps->code_rate_HP = FEC_2_3; - break; - case CODE_RATE_3_4: - fe_tps->code_rate_HP = FEC_3_4; - break; - case CODE_RATE_5_6: - fe_tps->code_rate_HP = FEC_5_6; - break; - case CODE_RATE_7_8: - fe_tps->code_rate_HP = FEC_7_8; - break; - } - - /* extract code rate LP */ - switch (as10x_tps->code_rate_LP) { - case CODE_RATE_1_2: - fe_tps->code_rate_LP = FEC_1_2; - break; - case CODE_RATE_2_3: - fe_tps->code_rate_LP = FEC_2_3; - break; - case CODE_RATE_3_4: - fe_tps->code_rate_LP = FEC_3_4; - break; - case CODE_RATE_5_6: - fe_tps->code_rate_LP = FEC_5_6; - break; - case CODE_RATE_7_8: - fe_tps->code_rate_LP = FEC_7_8; - break; - } - - /* extract guard interval */ - switch (as10x_tps->guard_interval) { - case GUARD_INT_1_32: - fe_tps->guard_interval = GUARD_INTERVAL_1_32; - break; - case GUARD_INT_1_16: - fe_tps->guard_interval = GUARD_INTERVAL_1_16; - break; - case GUARD_INT_1_8: - fe_tps->guard_interval = GUARD_INTERVAL_1_8; - break; - case GUARD_INT_1_4: - fe_tps->guard_interval = GUARD_INTERVAL_1_4; - break; - } - - /* extract transmission mode */ - switch (as10x_tps->transmission_mode) { - case TRANS_MODE_2K: - fe_tps->transmission_mode = TRANSMISSION_MODE_2K; - break; - case TRANS_MODE_8K: - fe_tps->transmission_mode = TRANSMISSION_MODE_8K; - break; - } -} - static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) { uint8_t c; @@ -300,7 +202,7 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe) static int as102_fe_get_frontend(struct dvb_frontend *fe) { struct as102_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret = 0; struct as10x_tps tps = { 0 }; @@ -310,12 +212,105 @@ static int as102_fe_get_frontend(struct dvb_frontend *fe) /* send abilis command: GET_TPS */ ret = as10x_cmd_get_tps(state->bus_adap, &tps); - if (ret == 0) - as10x_fe_copy_tps_parameters(p, &tps); - mutex_unlock(&state->bus_adap->lock); - return (ret < 0) ? -EINVAL : 0; + if (ret < 0) + return ret; + + /* extract constellation */ + switch (tps.modulation) { + case CONST_QPSK: + c->modulation = QPSK; + break; + case CONST_QAM16: + c->modulation = QAM_16; + break; + case CONST_QAM64: + c->modulation = QAM_64; + break; + } + + /* extract hierarchy */ + switch (tps.hierarchy) { + case HIER_NONE: + c->hierarchy = HIERARCHY_NONE; + break; + case HIER_ALPHA_1: + c->hierarchy = HIERARCHY_1; + break; + case HIER_ALPHA_2: + c->hierarchy = HIERARCHY_2; + break; + case HIER_ALPHA_4: + c->hierarchy = HIERARCHY_4; + break; + } + + /* extract code rate HP */ + switch (tps.code_rate_HP) { + case CODE_RATE_1_2: + c->code_rate_HP = FEC_1_2; + break; + case CODE_RATE_2_3: + c->code_rate_HP = FEC_2_3; + break; + case CODE_RATE_3_4: + c->code_rate_HP = FEC_3_4; + break; + case CODE_RATE_5_6: + c->code_rate_HP = FEC_5_6; + break; + case CODE_RATE_7_8: + c->code_rate_HP = FEC_7_8; + break; + } + + /* extract code rate LP */ + switch (tps.code_rate_LP) { + case CODE_RATE_1_2: + c->code_rate_LP = FEC_1_2; + break; + case CODE_RATE_2_3: + c->code_rate_LP = FEC_2_3; + break; + case CODE_RATE_3_4: + c->code_rate_LP = FEC_3_4; + break; + case CODE_RATE_5_6: + c->code_rate_LP = FEC_5_6; + break; + case CODE_RATE_7_8: + c->code_rate_LP = FEC_7_8; + break; + } + + /* extract guard interval */ + switch (tps.guard_interval) { + case GUARD_INT_1_32: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case GUARD_INT_1_16: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case GUARD_INT_1_8: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case GUARD_INT_1_4: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + /* extract transmission mode */ + switch (tps.transmission_mode) { + case TRANS_MODE_2K: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case TRANS_MODE_8K: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + + return 0; } static int as102_fe_get_tune_settings(struct dvb_frontend *fe, -- GitLab From 47f79129ecf5fd12d847c2e63b6ce39d1df4a648 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:22 -0300 Subject: [PATCH 0567/5088] [media] as102: prepare as102_fe to be compiled as a module Remove the dependencies of as102_cmd from as102, in order to allow it to be compiled as a separate module. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_drv.c | 116 +++++++++++++++++++++++++ drivers/media/usb/as102/as102_drv.h | 8 +- drivers/media/usb/as102/as102_fe.c | 105 ++++++---------------- drivers/media/usb/as102/as102_fe.h | 29 +++++++ drivers/media/usb/as102/as10x_cmd.h | 2 - drivers/media/usb/as102/as10x_handle.h | 3 +- drivers/media/usb/as102/as10x_types.h | 2 - 7 files changed, 179 insertions(+), 86 deletions(-) create mode 100644 drivers/media/usb/as102/as102_fe.h diff --git a/drivers/media/usb/as102/as102_drv.c b/drivers/media/usb/as102/as102_drv.c index ff5bd2e5657a..8be1474b2c36 100644 --- a/drivers/media/usb/as102/as102_drv.c +++ b/drivers/media/usb/as102/as102_drv.c @@ -24,6 +24,8 @@ /* header file for usb device driver*/ #include "as102_drv.h" +#include "as10x_cmd.h" +#include "as102_fe.h" #include "as102_fw.h" #include "dvbdev.h" @@ -176,6 +178,119 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return 0; } +static int as102_set_tune(void *priv, struct as10x_tune_args *tune_args) +{ + struct as10x_bus_adapter_t *bus_adap = priv; + int ret; + + /* Set frontend arguments */ + if (mutex_lock_interruptible(&bus_adap->lock)) + return -EBUSY; + + ret = as10x_cmd_set_tune(bus_adap, tune_args); + if (ret != 0) + dev_dbg(&bus_adap->usb_dev->dev, + "as10x_cmd_set_tune failed. (err = %d)\n", ret); + + mutex_unlock(&bus_adap->lock); + + return ret; +} + +static int as102_get_tps(void *priv, struct as10x_tps *tps) +{ + struct as10x_bus_adapter_t *bus_adap = priv; + int ret; + + if (mutex_lock_interruptible(&bus_adap->lock)) + return -EBUSY; + + /* send abilis command: GET_TPS */ + ret = as10x_cmd_get_tps(bus_adap, tps); + + mutex_unlock(&bus_adap->lock); + + return ret; +} + +static int as102_get_status(void *priv, struct as10x_tune_status *tstate) +{ + struct as10x_bus_adapter_t *bus_adap = priv; + int ret; + + if (mutex_lock_interruptible(&bus_adap->lock)) + return -EBUSY; + + /* send abilis command: GET_TUNE_STATUS */ + ret = as10x_cmd_get_tune_status(bus_adap, tstate); + if (ret < 0) { + dev_dbg(&bus_adap->usb_dev->dev, + "as10x_cmd_get_tune_status failed (err = %d)\n", + ret); + } + + mutex_unlock(&bus_adap->lock); + + return ret; +} + +static int as102_get_stats(void *priv, struct as10x_demod_stats *demod_stats) +{ + struct as10x_bus_adapter_t *bus_adap = priv; + int ret; + + if (mutex_lock_interruptible(&bus_adap->lock)) + return -EBUSY; + + /* send abilis command: GET_TUNE_STATUS */ + ret = as10x_cmd_get_demod_stats(bus_adap, demod_stats); + if (ret < 0) { + dev_dbg(&bus_adap->usb_dev->dev, + "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); + } else { + dev_dbg(&bus_adap->usb_dev->dev, + "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n", + demod_stats->frame_count, + demod_stats->bad_frame_count, + demod_stats->bytes_fixed_by_rs, + demod_stats->mer); + } + mutex_unlock(&bus_adap->lock); + + return ret; +} + +static int as102_stream_ctrl(void *priv, int acquire, uint32_t elna_cfg) +{ + struct as10x_bus_adapter_t *bus_adap = priv; + int ret; + + if (mutex_lock_interruptible(&bus_adap->lock)) + return -EBUSY; + + if (acquire) { + if (elna_enable) + as10x_cmd_set_context(bus_adap, + CONTEXT_LNA, elna_cfg); + + ret = as10x_cmd_turn_on(bus_adap); + } else { + ret = as10x_cmd_turn_off(bus_adap); + } + + mutex_unlock(&bus_adap->lock); + + return ret; +} + +static const struct as102_fe_ops as102_fe_ops = { + .set_tune = as102_set_tune, + .get_tps = as102_get_tps, + .get_status = as102_get_status, + .get_stats = as102_get_stats, + .stream_ctrl = as102_stream_ctrl, +}; + int as102_dvb_register(struct as102_dev_t *as102_dev) { struct device *dev = &as102_dev->bus_adap.usb_dev->dev; @@ -218,6 +333,7 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) /* Attach the frontend */ as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name, + &as102_fe_ops, &as102_dev->bus_adap, as102_dev->elna_cfg); if (!as102_dev->dvb_fe) { diff --git a/drivers/media/usb/as102/as102_drv.h b/drivers/media/usb/as102/as102_drv.h index 1e2a76d3c517..9430d30163a3 100644 --- a/drivers/media/usb/as102/as102_drv.h +++ b/drivers/media/usb/as102/as102_drv.h @@ -13,10 +13,13 @@ * GNU General Public License for more details. */ +#ifndef _AS102_DRV_H +#define _AS102_DRV_H #include #include #include #include +#include "as10x_handle.h" #include "as10x_cmd.h" #include "as102_usb_drv.h" @@ -77,7 +80,4 @@ struct as102_dev_t { int as102_dvb_register(struct as102_dev_t *dev); void as102_dvb_unregister(struct as102_dev_t *dev); -/* FIXME: move it to a separate header */ -struct dvb_frontend *as102_attach(const char *name, - struct as10x_bus_adapter_t *bus_adap, - uint8_t elna_cfg); +#endif \ No newline at end of file diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/usb/as102/as102_fe.c index 0cd19f23eca9..f57560c191ae 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/usb/as102/as102_fe.c @@ -13,15 +13,17 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ -#include "as102_drv.h" -#include "as10x_types.h" -#include "as10x_cmd.h" + +#include + +#include "as102_fe.h" struct as102_state { struct dvb_frontend frontend; struct as10x_demod_stats demod_stats; - struct as10x_bus_adapter_t *bus_adap; + const struct as102_fe_ops *ops; + void *priv; uint8_t elna_cfg; /* signal strength */ @@ -62,7 +64,6 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe) { struct as102_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret = 0; struct as10x_tune_args tune_args = { 0 }; /* set frequency */ @@ -186,17 +187,7 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe) } /* Set frontend arguments */ - if (mutex_lock_interruptible(&state->bus_adap->lock)) - return -EBUSY; - - ret = as10x_cmd_set_tune(state->bus_adap, &tune_args); - if (ret != 0) - dev_dbg(&state->bus_adap->usb_dev->dev, - "as10x_cmd_set_tune failed. (err = %d)\n", ret); - - mutex_unlock(&state->bus_adap->lock); - - return (ret < 0) ? -EINVAL : 0; + return state->ops->set_tune(state->priv, &tune_args); } static int as102_fe_get_frontend(struct dvb_frontend *fe) @@ -206,14 +197,8 @@ static int as102_fe_get_frontend(struct dvb_frontend *fe) int ret = 0; struct as10x_tps tps = { 0 }; - if (mutex_lock_interruptible(&state->bus_adap->lock)) - return -EBUSY; - /* send abilis command: GET_TPS */ - ret = as10x_cmd_get_tps(state->bus_adap, &tps); - - mutex_unlock(&state->bus_adap->lock); - + ret = state->ops->get_tps(state->priv, &tps); if (ret < 0) return ret; @@ -321,24 +306,16 @@ static int as102_fe_get_tune_settings(struct dvb_frontend *fe, return 0; } - static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) { int ret = 0; struct as102_state *state = fe->demodulator_priv; struct as10x_tune_status tstate = { 0 }; - if (mutex_lock_interruptible(&state->bus_adap->lock)) - return -EBUSY; - /* send abilis command: GET_TUNE_STATUS */ - ret = as10x_cmd_get_tune_status(state->bus_adap, &tstate); - if (ret < 0) { - dev_dbg(&state->bus_adap->usb_dev->dev, - "as10x_cmd_get_tune_status failed (err = %d)\n", - ret); - goto out; - } + ret = state->ops->get_status(state->priv, &tstate); + if (ret < 0) + return ret; state->signal_strength = tstate.signal_strength; state->ber = tstate.BER; @@ -358,31 +335,19 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) *status = TUNE_STATUS_NOT_TUNED; } - dev_dbg(&state->bus_adap->usb_dev->dev, - "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", - tstate.tune_state, tstate.signal_strength, - tstate.PER, tstate.BER); - - if (*status & FE_HAS_LOCK) { - if (as10x_cmd_get_demod_stats(state->bus_adap, - (struct as10x_demod_stats *) &state->demod_stats) < 0) { - memset(&state->demod_stats, 0, sizeof(state->demod_stats)); - dev_dbg(&state->bus_adap->usb_dev->dev, - "as10x_cmd_get_demod_stats failed (probably not tuned)\n"); - } else { - dev_dbg(&state->bus_adap->usb_dev->dev, - "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n", - state->demod_stats.frame_count, - state->demod_stats.bad_frame_count, - state->demod_stats.bytes_fixed_by_rs, - state->demod_stats.mer); - } - } else { + pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", + tstate.tune_state, tstate.signal_strength, + tstate.PER, tstate.BER); + + if (!(*status & FE_HAS_LOCK)) { memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + return 0; } -out: - mutex_unlock(&state->bus_adap->lock); + ret = state->ops->get_stats(state->priv, &state->demod_stats); + if (ret < 0) + memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + return ret; } @@ -436,24 +401,9 @@ static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) { struct as102_state *state = fe->demodulator_priv; - int ret; - - if (mutex_lock_interruptible(&state->bus_adap->lock)) - return -EBUSY; - if (acquire) { - if (elna_enable) - as10x_cmd_set_context(state->bus_adap, - CONTEXT_LNA, state->elna_cfg); - - ret = as10x_cmd_turn_on(state->bus_adap); - } else { - ret = as10x_cmd_turn_off(state->bus_adap); - } - - mutex_unlock(&state->bus_adap->lock); - - return ret; + return state->ops->stream_ctrl(state->priv, acquire, + state->elna_cfg); } static struct dvb_frontend_ops as102_fe_ops = { @@ -488,7 +438,8 @@ static struct dvb_frontend_ops as102_fe_ops = { }; struct dvb_frontend *as102_attach(const char *name, - struct as10x_bus_adapter_t *bus_adap, + const struct as102_fe_ops *ops, + void *priv, uint8_t elna_cfg) { struct as102_state *state; @@ -496,13 +447,13 @@ struct dvb_frontend *as102_attach(const char *name, state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); if (state == NULL) { - dev_err(&bus_adap->usb_dev->dev, - "%s: unable to allocate memory for state\n", __func__); + pr_err("%s: unable to allocate memory for state\n", __func__); return NULL; } fe = &state->frontend; fe->demodulator_priv = state; - state->bus_adap = bus_adap; + state->ops = ops; + state->priv = priv; state->elna_cfg = elna_cfg; /* init frontend callback ops */ diff --git a/drivers/media/usb/as102/as102_fe.h b/drivers/media/usb/as102/as102_fe.h new file mode 100644 index 000000000000..4098cf8f8cf9 --- /dev/null +++ b/drivers/media/usb/as102/as102_fe.h @@ -0,0 +1,29 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2014 Mauro Carvalho Chehab + * + * 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, 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 "as10x_types.h" + +struct as102_fe_ops { + int (*set_tune)(void *priv, struct as10x_tune_args *tune_args); + int (*get_tps)(void *priv, struct as10x_tps *tps); + int (*get_status)(void *priv, struct as10x_tune_status *tstate); + int (*get_stats)(void *priv, struct as10x_demod_stats *demod_stats); + int (*stream_ctrl)(void *priv, int acquire, uint32_t elna_cfg); +}; + +struct dvb_frontend *as102_attach(const char *name, + const struct as102_fe_ops *ops, + void *priv, + uint8_t elna_cfg); diff --git a/drivers/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h index 1c9ea2c2175e..83c0440dba2f 100644 --- a/drivers/media/usb/as102/as10x_cmd.h +++ b/drivers/media/usb/as102/as10x_cmd.h @@ -15,9 +15,7 @@ #ifndef _AS10X_CMD_H_ #define _AS10X_CMD_H_ -#ifdef __KERNEL__ #include -#endif #include "as10x_types.h" diff --git a/drivers/media/usb/as102/as10x_handle.h b/drivers/media/usb/as102/as10x_handle.h index e535fffbcd94..d6b58c770500 100644 --- a/drivers/media/usb/as102/as10x_handle.h +++ b/drivers/media/usb/as102/as10x_handle.h @@ -12,7 +12,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ -#ifdef __KERNEL__ +#ifndef _AS10X_HANDLE_H +#define _AS10X_HANDLE_H struct as10x_bus_adapter_t; struct as102_dev_t; diff --git a/drivers/media/usb/as102/as10x_types.h b/drivers/media/usb/as102/as10x_types.h index f82d51e542e3..80a5398b580f 100644 --- a/drivers/media/usb/as102/as10x_types.h +++ b/drivers/media/usb/as102/as10x_types.h @@ -15,8 +15,6 @@ #ifndef _AS10X_TYPES_H_ #define _AS10X_TYPES_H_ -#include "as10x_handle.h" - /*********************************/ /* MACRO DEFINITIONS */ /*********************************/ -- GitLab From dcae77814865122ed411de1a4e8ebd02796cf3c4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:23 -0300 Subject: [PATCH 0568/5088] [media] as102-fe: make it an independent driver Move as102-fe to dvb-frontends directory and make it an independent driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 5 +++++ drivers/media/dvb-frontends/Makefile | 2 +- drivers/media/{usb/as102 => dvb-frontends}/as102_fe.c | 4 ++++ drivers/media/{usb/as102 => dvb-frontends}/as102_fe.h | 2 +- .../as102/as10x_types.h => dvb-frontends/as102_fe_types.h} | 0 drivers/media/usb/as102/Makefile | 3 ++- drivers/media/usb/as102/as10x_cmd.c | 1 - drivers/media/usb/as102/as10x_cmd.h | 2 +- drivers/media/usb/as102/as10x_cmd_cfg.c | 1 - 9 files changed, 14 insertions(+), 6 deletions(-) rename drivers/media/{usb/as102 => dvb-frontends}/as102_fe.c (98%) rename drivers/media/{usb/as102 => dvb-frontends}/as102_fe.h (97%) rename drivers/media/{usb/as102/as10x_types.h => dvb-frontends/as102_fe_types.h} (100%) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index fe0ddcca192c..aa5ae224626a 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -471,6 +471,11 @@ config DVB_SI2168 help Say Y when you want to support this frontend. +config DVB_AS102_FE + tristate + depends on DVB_CORE + default DVB_AS102 + comment "DVB-C (cable) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index edf103d45920..fc4e689d4b67 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -113,4 +113,4 @@ obj-$(CONFIG_DVB_RTL2832) += rtl2832.o obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o obj-$(CONFIG_DVB_AF9033) += af9033.o - +obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o diff --git a/drivers/media/usb/as102/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c similarity index 98% rename from drivers/media/usb/as102/as102_fe.c rename to drivers/media/dvb-frontends/as102_fe.c index f57560c191ae..b272e4ea1860 100644 --- a/drivers/media/usb/as102/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -464,3 +464,7 @@ struct dvb_frontend *as102_attach(const char *name, } EXPORT_SYMBOL_GPL(as102_attach); + +MODULE_DESCRIPTION("as102-fe"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pierrick Hascoet "); diff --git a/drivers/media/usb/as102/as102_fe.h b/drivers/media/dvb-frontends/as102_fe.h similarity index 97% rename from drivers/media/usb/as102/as102_fe.h rename to drivers/media/dvb-frontends/as102_fe.h index 4098cf8f8cf9..a7c91430ca3d 100644 --- a/drivers/media/usb/as102/as102_fe.h +++ b/drivers/media/dvb-frontends/as102_fe.h @@ -13,7 +13,7 @@ * GNU General Public License for more details. */ -#include "as10x_types.h" +#include "as102_fe_types.h" struct as102_fe_ops { int (*set_tune)(void *priv, struct as10x_tune_args *tune_args); diff --git a/drivers/media/usb/as102/as10x_types.h b/drivers/media/dvb-frontends/as102_fe_types.h similarity index 100% rename from drivers/media/usb/as102/as10x_types.h rename to drivers/media/dvb-frontends/as102_fe_types.h diff --git a/drivers/media/usb/as102/Makefile b/drivers/media/usb/as102/Makefile index 8916d8a909bc..22f43eee4a3b 100644 --- a/drivers/media/usb/as102/Makefile +++ b/drivers/media/usb/as102/Makefile @@ -1,6 +1,7 @@ dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \ - as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o + as102_usb_drv.o as10x_cmd_cfg.o obj-$(CONFIG_DVB_AS102) += dvb-as102.o ccflags-y += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/usb/as102/as10x_cmd.c b/drivers/media/usb/as102/as10x_cmd.c index 8868c52500ee..ef238022dfe5 100644 --- a/drivers/media/usb/as102/as10x_cmd.c +++ b/drivers/media/usb/as102/as10x_cmd.c @@ -16,7 +16,6 @@ #include #include "as102_drv.h" -#include "as10x_types.h" #include "as10x_cmd.h" /** diff --git a/drivers/media/usb/as102/as10x_cmd.h b/drivers/media/usb/as102/as10x_cmd.h index 83c0440dba2f..09134f73ba3d 100644 --- a/drivers/media/usb/as102/as10x_cmd.h +++ b/drivers/media/usb/as102/as10x_cmd.h @@ -17,7 +17,7 @@ #include -#include "as10x_types.h" +#include "as102_fe_types.h" /*********************************/ /* MACRO DEFINITIONS */ diff --git a/drivers/media/usb/as102/as10x_cmd_cfg.c b/drivers/media/usb/as102/as10x_cmd_cfg.c index 833463343ada..6f9dea1d860b 100644 --- a/drivers/media/usb/as102/as10x_cmd_cfg.c +++ b/drivers/media/usb/as102/as10x_cmd_cfg.c @@ -15,7 +15,6 @@ #include #include "as102_drv.h" -#include "as10x_types.h" #include "as10x_cmd.h" /***************************/ -- GitLab From 4628f993bf66d595226d019e87a4baca636b71e2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 18:50:24 -0300 Subject: [PATCH 0569/5088] [media] as102: add missing viterbi lock In order to get FE_HAS_SYNC, the viterbi should already be locked too. So, add the missing FE_HAS_VITERBI lock. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/as102_fe.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index b272e4ea1860..ef4c3c667782 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -325,11 +325,12 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; break; case TUNE_STATUS_STREAM_DETECTED: - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | + FE_HAS_VITERBI; break; case TUNE_STATUS_STREAM_TUNED: *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | - FE_HAS_LOCK; + FE_HAS_LOCK | FE_HAS_VITERBI; break; default: *status = TUNE_STATUS_NOT_TUNED; -- GitLab From 5b6aa199196220a5901c8d9cbad497fea347850a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Aug 2014 21:35:44 -0300 Subject: [PATCH 0570/5088] [media] as102-fe: Add a release function This is needed to free state and for dvb_detach() to be called. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/as102_fe.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index ef4c3c667782..493665899565 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -407,6 +407,14 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) state->elna_cfg); } +static void as102_fe_release(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + + kfree(state); +} + + static struct dvb_frontend_ops as102_fe_ops = { .delsys = { SYS_DVBT }, .info = { @@ -436,6 +444,7 @@ static struct dvb_frontend_ops as102_fe_ops = { .read_signal_strength = as102_fe_read_signal_strength, .read_ucblocks = as102_fe_read_ucblocks, .ts_bus_ctrl = as102_fe_ts_bus_ctrl, + .release = as102_fe_release, }; struct dvb_frontend *as102_attach(const char *name, -- GitLab From 23d3090f8b44ab42162e99e8584445bc25b8922f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 5 Aug 2014 05:11:13 -0300 Subject: [PATCH 0571/5088] [media] vmalloc_sg: off by one in error handling The "i--" needs to happen at the start of the loop or it will try to release something bogus (probably it will crash) and it won't release the first ->vaddr_page[]. Fixes: 7b4eeed174b7 ('[media] vmalloc_sg: make sure all pages in vmalloc area are really DMA-ready') Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf-dma-sg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 3c8cc023a5a5..3ff15f1c9d70 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -253,9 +253,11 @@ int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, return 0; out_free_pages: while (i > 0) { - void *addr = page_address(dma->vaddr_pages[i]); - dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]); + void *addr; + i--; + addr = page_address(dma->vaddr_pages[i]); + dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]); } kfree(dma->dma_addr); dma->dma_addr = NULL; -- GitLab From f035eb4e976ef5a059e30bc91cfd310ff030a7d3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Aug 2014 03:47:14 -0300 Subject: [PATCH 0572/5088] [media] videobuf2: fix lockdep warning The following lockdep warning has been there ever since commit a517cca6b24fc54ac209e44118ec8962051662e3 one year ago: [ 403.117947] ====================================================== [ 403.117949] [ INFO: possible circular locking dependency detected ] [ 403.117953] 3.16.0-rc6-test-media #961 Not tainted [ 403.117954] ------------------------------------------------------- [ 403.117956] v4l2-ctl/15377 is trying to acquire lock: [ 403.117959] (&dev->mutex#3){+.+.+.}, at: [] vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.117974] [ 403.117974] but task is already holding lock: [ 403.117976] (&mm->mmap_sem){++++++}, at: [] vm_mmap_pgoff+0x6f/0xc0 [ 403.117987] [ 403.117987] which lock already depends on the new lock. [ 403.117987] [ 403.117990] [ 403.117990] the existing dependency chain (in reverse order) is: [ 403.117992] [ 403.117992] -> #1 (&mm->mmap_sem){++++++}: [ 403.117997] [] validate_chain.isra.39+0x5fc/0x9a0 [ 403.118006] [] __lock_acquire+0x4d3/0xd30 [ 403.118010] [] lock_acquire+0xa7/0x160 [ 403.118014] [] might_fault+0x7c/0xb0 [ 403.118018] [] video_usercopy+0x425/0x610 [videodev] [ 403.118028] [] video_ioctl2+0x15/0x20 [videodev] [ 403.118034] [] v4l2_ioctl+0x184/0x1a0 [videodev] [ 403.118040] [] do_vfs_ioctl+0x2f0/0x4f0 [ 403.118307] [] SyS_ioctl+0x81/0xa0 [ 403.118311] [] system_call_fastpath+0x16/0x1b [ 403.118319] [ 403.118319] -> #0 (&dev->mutex#3){+.+.+.}: [ 403.118324] [] check_prevs_add+0x746/0x9f0 [ 403.118329] [] validate_chain.isra.39+0x5fc/0x9a0 [ 403.118333] [] __lock_acquire+0x4d3/0xd30 [ 403.118336] [] lock_acquire+0xa7/0x160 [ 403.118340] [] mutex_lock_interruptible_nested+0x64/0x640 [ 403.118344] [] vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118349] [] v4l2_mmap+0x62/0xa0 [videodev] [ 403.118354] [] mmap_region+0x3d0/0x5d0 [ 403.118359] [] do_mmap_pgoff+0x31d/0x400 [ 403.118363] [] vm_mmap_pgoff+0x90/0xc0 [ 403.118366] [] SyS_mmap_pgoff+0x1df/0x2a0 [ 403.118369] [] SyS_mmap+0x22/0x30 [ 403.118376] [] system_call_fastpath+0x16/0x1b [ 403.118381] [ 403.118381] other info that might help us debug this: [ 403.118381] [ 403.118383] Possible unsafe locking scenario: [ 403.118383] [ 403.118385] CPU0 CPU1 [ 403.118387] ---- ---- [ 403.118388] lock(&mm->mmap_sem); [ 403.118391] lock(&dev->mutex#3); [ 403.118394] lock(&mm->mmap_sem); [ 403.118397] lock(&dev->mutex#3); [ 403.118400] [ 403.118400] *** DEADLOCK *** [ 403.118400] [ 403.118403] 1 lock held by v4l2-ctl/15377: [ 403.118405] #0: (&mm->mmap_sem){++++++}, at: [] vm_mmap_pgoff+0x6f/0xc0 [ 403.118411] [ 403.118411] stack backtrace: [ 403.118415] CPU: 0 PID: 15377 Comm: v4l2-ctl Not tainted 3.16.0-rc6-test-media #961 [ 403.118418] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/31/2013 [ 403.118420] ffffffff82a6c9d0 ffff8800af37fb00 ffffffff819916a2 ffffffff82a6c9d0 [ 403.118425] ffff8800af37fb40 ffffffff810d5715 ffff8802308e4200 0000000000000000 [ 403.118429] ffff8802308e4a48 ffff8802308e4a48 ffff8802308e4200 0000000000000001 [ 403.118433] Call Trace: [ 403.118441] [] dump_stack+0x4e/0x7a [ 403.118445] [] print_circular_bug+0x1d5/0x2a0 [ 403.118449] [] check_prevs_add+0x746/0x9f0 [ 403.118455] [] ? find_vmap_area+0x42/0x70 [ 403.118459] [] validate_chain.isra.39+0x5fc/0x9a0 [ 403.118463] [] __lock_acquire+0x4d3/0xd30 [ 403.118468] [] lock_acquire+0xa7/0x160 [ 403.118472] [] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118476] [] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118480] [] mutex_lock_interruptible_nested+0x64/0x640 [ 403.118484] [] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118488] [] ? vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118493] [] ? mark_held_locks+0x75/0xa0 [ 403.118497] [] vb2_fop_mmap+0x33/0x90 [videobuf2_core] [ 403.118502] [] v4l2_mmap+0x62/0xa0 [videodev] [ 403.118506] [] mmap_region+0x3d0/0x5d0 [ 403.118510] [] do_mmap_pgoff+0x31d/0x400 [ 403.118513] [] vm_mmap_pgoff+0x90/0xc0 [ 403.118517] [] SyS_mmap_pgoff+0x1df/0x2a0 [ 403.118521] [] SyS_mmap+0x22/0x30 [ 403.118525] [] system_call_fastpath+0x16/0x1b The reason is that vb2_fop_mmap and vb2_fop_get_unmapped_area take the core lock while they are called with the mmap_sem semaphore held. But elsewhere in the code the core lock is taken first but calls to copy_to/from_user() can take the mmap_sem semaphore as well, potentially causing a classical A-B/B-A deadlock. However, the mmap/get_unmapped_area calls really shouldn't take the core lock at all. So what would happen if they don't take the core lock anymore? There are two situations that need to be taken into account: calling mmap while new buffers are being added and calling mmap while buffers are being deleted. The first case works almost fine without a lock: in all cases mmap relies on correctly filled-in q->num_buffers/q->num_planes values and those are only updated by reqbufs and create_buffers *after* any new buffers have been initialized completely. Except in one case: if an error occurred while allocating the buffers it will increase num_buffers and rely on __vb2_queue_free to decrease it again. So there is a short period where the buffer information may be wrong. The second case definitely does pose a problem: buffers may be in the process of being deleted, without the internal structure being updated. In order to fix this a new mutex is added to vb2_queue that is taken when buffers are allocated or deleted, and in vb2_mmap. That way vb2_mmap won't get stale buffer data. Note that this is a problem only for MEMORY_MMAP, so even though __qbuf_userptr and __qbuf_dmabuf also mess around with buffers (mem_priv in particular), this doesn't clash with vb2_mmap or vb2_get_unmapped_area since those are MMAP specific. As an additional bonus the hack in __buf_prepare, the USERPTR case, can be removed as well since mmap() no longer takes the core lock. All in all a much cleaner solution. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Acked-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 56 ++++++++---------------- include/media/videobuf2-core.h | 2 + 2 files changed, 21 insertions(+), 37 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index c359006074a8..eb86913349fc 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -882,7 +882,9 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * We already have buffers allocated, so first check if they * are not in use and can be freed. */ + mutex_lock(&q->mmap_lock); if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) { + mutex_unlock(&q->mmap_lock); dprintk(1, "memory in use, cannot free\n"); return -EBUSY; } @@ -894,6 +896,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) */ __vb2_queue_cancel(q); ret = __vb2_queue_free(q, q->num_buffers); + mutex_unlock(&q->mmap_lock); if (ret) return ret; @@ -955,6 +958,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) */ } + mutex_lock(&q->mmap_lock); q->num_buffers = allocated_buffers; if (ret < 0) { @@ -963,8 +967,10 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * from q->num_buffers. */ __vb2_queue_free(q, allocated_buffers); + mutex_unlock(&q->mmap_lock); return ret; } + mutex_unlock(&q->mmap_lock); /* * Return the number of successfully allocated buffers @@ -1061,6 +1067,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create */ } + mutex_lock(&q->mmap_lock); q->num_buffers += allocated_buffers; if (ret < 0) { @@ -1069,8 +1076,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create * from q->num_buffers. */ __vb2_queue_free(q, allocated_buffers); + mutex_unlock(&q->mmap_lock); return -ENOMEM; } + mutex_unlock(&q->mmap_lock); /* * Return the number of successfully allocated buffers @@ -1582,7 +1591,6 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) { struct vb2_queue *q = vb->vb2_queue; - struct rw_semaphore *mmap_sem; int ret; ret = __verify_length(vb, b); @@ -1619,26 +1627,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) ret = __qbuf_mmap(vb, b); break; case V4L2_MEMORY_USERPTR: - /* - * In case of user pointer buffers vb2 allocators need to get - * direct access to userspace pages. This requires getting - * the mmap semaphore for read access in the current process - * structure. The same semaphore is taken before calling mmap - * operation, while both qbuf/prepare_buf and mmap are called - * by the driver or v4l2 core with the driver's lock held. - * To avoid an AB-BA deadlock (mmap_sem then driver's lock in - * mmap and driver's lock then mmap_sem in qbuf/prepare_buf), - * the videobuf2 core releases the driver's lock, takes - * mmap_sem and then takes the driver's lock again. - */ - mmap_sem = ¤t->mm->mmap_sem; - call_void_qop(q, wait_prepare, q); - down_read(mmap_sem); - call_void_qop(q, wait_finish, q); - ret = __qbuf_userptr(vb, b); - - up_read(mmap_sem); break; case V4L2_MEMORY_DMABUF: ret = __qbuf_dmabuf(vb, b); @@ -2485,7 +2474,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) return -EINVAL; } + mutex_lock(&q->mmap_lock); ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma); + mutex_unlock(&q->mmap_lock); if (ret) return ret; @@ -2504,6 +2495,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, unsigned long off = pgoff << PAGE_SHIFT; struct vb2_buffer *vb; unsigned int buffer, plane; + void *vaddr; int ret; if (q->memory != V4L2_MEMORY_MMAP) { @@ -2520,7 +2512,8 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, vb = q->bufs[buffer]; - return (unsigned long)vb2_plane_vaddr(vb, plane); + vaddr = vb2_plane_vaddr(vb, plane); + return vaddr ? (unsigned long)vaddr : -EINVAL; } EXPORT_SYMBOL_GPL(vb2_get_unmapped_area); #endif @@ -2660,6 +2653,7 @@ int vb2_queue_init(struct vb2_queue *q) INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); + mutex_init(&q->mmap_lock); init_waitqueue_head(&q->done_wq); if (q->buf_struct_size == 0) @@ -2681,7 +2675,9 @@ void vb2_queue_release(struct vb2_queue *q) { __vb2_cleanup_fileio(q); __vb2_queue_cancel(q); + mutex_lock(&q->mmap_lock); __vb2_queue_free(q, q->num_buffers); + mutex_unlock(&q->mmap_lock); } EXPORT_SYMBOL_GPL(vb2_queue_release); @@ -3346,15 +3342,8 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_expbuf); int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma) { struct video_device *vdev = video_devdata(file); - struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; - int err; - if (lock && mutex_lock_interruptible(lock)) - return -ERESTARTSYS; - err = vb2_mmap(vdev->queue, vma); - if (lock) - mutex_unlock(lock); - return err; + return vb2_mmap(vdev->queue, vma); } EXPORT_SYMBOL_GPL(vb2_fop_mmap); @@ -3473,15 +3462,8 @@ unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct video_device *vdev = video_devdata(file); - struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; - int ret; - if (lock && mutex_lock_interruptible(lock)) - return -ERESTARTSYS; - ret = vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags); - if (lock) - mutex_unlock(lock); - return ret; + return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags); } EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area); #endif diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index fc910a622451..5a10d8d695b4 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -366,6 +366,7 @@ struct v4l2_fh; * cannot be started unless at least this number of buffers * have been queued into the driver. * + * @mmap_lock: private mutex used when buffers are allocated/freed/mmapped * @memory: current memory type used * @bufs: videobuf buffer structures * @num_buffers: number of allocated/used buffers @@ -399,6 +400,7 @@ struct vb2_queue { u32 min_buffers_needed; /* private: internal use only */ + struct mutex mmap_lock; enum v4l2_memory memory; struct vb2_buffer *bufs[VIDEO_MAX_FRAME]; unsigned int num_buffers; -- GitLab From 83acb75d0dd37bd2eb24168f26d01c747ece3fc7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Aug 2014 04:38:09 -0300 Subject: [PATCH 0573/5088] [media] DocBook media: fix order of v4l2_edid fields The order of the last two fields in the G/S_EDID specification was swapped from what is in the actual struct. Fix this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-g-edid.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml index ce4563b87131..fa91651978e0 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml @@ -124,18 +124,18 @@ maximum number of blocks as defined by the standard). When you set the EDID and blocks is 0, then the EDID is disabled or erased. - - __u8 * - edid - Pointer to memory that contains the EDID. The minimum size is - blocks * 128. - __u32 reserved[5] Reserved for future extensions. Applications and drivers must set the array to zero. + + __u8 * + edid + Pointer to memory that contains the EDID. The minimum size is + blocks * 128. + -- GitLab From 0821344d9e805912f1971c58318547ea62984321 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Aug 2014 09:59:02 -0300 Subject: [PATCH 0574/5088] [media] vb2: use pr_info instead of pr_debug Modern kernels enable dynamic printk support, which is fine, except when it is combined with a debug module option. Enabling debug in videobuf2-core now produces no debugging unless it is also enabled through the dynamic printk support in debugfs. Either use a debug module option + pr_info, or use pr_debug without a debug module option. In this case the fact that you can set various debug levels is very useful, so I believe that for videobuf2-core.c we should use pr_info. The mix of the two is very confusing: I've spent too much time already trying to figure out why I am not seeing any debug output in the kernel log when I do: echo 1 >/sys/modules/videobuf2_core/parameters/debug Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index eb86913349fc..5b808e25fc09 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -36,7 +36,7 @@ module_param(debug, int, 0644); #define dprintk(level, fmt, arg...) \ do { \ if (debug >= level) \ - pr_debug("vb2: %s: " fmt, __func__, ## arg); \ + pr_info("vb2: %s: " fmt, __func__, ## arg); \ } while (0) #ifdef CONFIG_VIDEO_ADV_DEBUG -- GitLab From d720b7aff6481b99a42d484383d7e19d86323b5d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Aug 2014 12:19:12 -0300 Subject: [PATCH 0575/5088] [media] cx25840: Spelling s/compuations/computations/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c index e6588ee5bdb0..4cf8f18bf097 100644 --- a/drivers/media/i2c/cx25840/cx25840-ir.c +++ b/drivers/media/i2c/cx25840/cx25840-ir.c @@ -224,7 +224,7 @@ static inline unsigned int lpf_count_to_us(unsigned int count) } /* - * FIFO register pulse width count compuations + * FIFO register pulse width count computations */ static u32 clock_divider_to_resolution(u16 divider) { -- GitLab From 43e9d4ab0c14ccff3ed27f8e43274571e286f0ed Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Aug 2014 12:19:13 -0300 Subject: [PATCH 0576/5088] [media] cx23885: Spelling s/compuations/computations/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23888-ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index 2c951dec2d33..c2ff5fc01157 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -263,7 +263,7 @@ static inline unsigned int lpf_count_to_us(unsigned int count) } /* - * FIFO register pulse width count compuations + * FIFO register pulse width count computations */ static u32 clock_divider_to_resolution(u16 divider) { -- GitLab From 6af6e9c84fcc8f86b15be607a9ae8afd1d1686ea Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 10 Aug 2014 06:41:31 -0300 Subject: [PATCH 0577/5088] [media] saa6752hs: Convert to devm_kzalloc() Using the managed function the kfree() calls can be removed from the probe error path and the remove handler. Signed-off-by: Axel Lin Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa6752hs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index 04e9e55018a5..4024ea6f1371 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -660,7 +660,7 @@ static const struct v4l2_subdev_ops saa6752hs_ops = { static int saa6752hs_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL); + struct saa6752hs_state *h; struct v4l2_subdev *sd; struct v4l2_ctrl_handler *hdl; u8 addr = 0x13; @@ -668,6 +668,8 @@ static int saa6752hs_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + + h = devm_kzalloc(&client->dev, sizeof(*h), GFP_KERNEL); if (h == NULL) return -ENOMEM; sd = &h->sd; @@ -752,7 +754,6 @@ static int saa6752hs_probe(struct i2c_client *client, int err = hdl->error; v4l2_ctrl_handler_free(hdl); - kfree(h); return err; } v4l2_ctrl_cluster(3, &h->video_bitrate_mode); @@ -767,7 +768,6 @@ static int saa6752hs_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(&to_state(sd)->hdl); - kfree(to_state(sd)); return 0; } -- GitLab From c8fa50549dc6e717e0941ee7092a973388253c7a Mon Sep 17 00:00:00 2001 From: Andreas Ruprecht Date: Sun, 10 Aug 2014 17:30:18 -0300 Subject: [PATCH 0578/5088] [media] drivers: media: pci: Makefile: Remove duplicate subdirectory from obj-y In the list of subdirectories compiled, b2c2/ appears twice. This patch removes one of the appearances. Signed-off-by: Andreas Ruprecht Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index e5b53fb569ef..dc2ebbe27306 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -10,7 +10,6 @@ obj-y += ttpci/ \ mantis/ \ ngene/ \ ddbridge/ \ - b2c2/ \ saa7146/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ -- GitLab From 63ddf68de52efaac40a9287e44266ac30e71dd36 Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Mon, 11 Aug 2014 18:42:22 -0300 Subject: [PATCH 0579/5088] [media] usbtv: add audio support Add an ALSA handler inside usbtv module, in order to make audio to work with those devices. Signed-off-by: Federico Simoncelli Tested-by: Lubomir Rintel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/Makefile | 3 +- drivers/media/usb/usbtv/usbtv-audio.c | 384 ++++++++++++++++++++++++++ drivers/media/usb/usbtv/usbtv-core.c | 16 +- drivers/media/usb/usbtv/usbtv-video.c | 9 +- drivers/media/usb/usbtv/usbtv.h | 21 +- 5 files changed, 423 insertions(+), 10 deletions(-) create mode 100644 drivers/media/usb/usbtv/usbtv-audio.c diff --git a/drivers/media/usb/usbtv/Makefile b/drivers/media/usb/usbtv/Makefile index 775316a88ea6..f555cf8a3dd2 100644 --- a/drivers/media/usb/usbtv/Makefile +++ b/drivers/media/usb/usbtv/Makefile @@ -1,4 +1,5 @@ usbtv-y := usbtv-core.o \ - usbtv-video.o + usbtv-video.o \ + usbtv-audio.o obj-$(CONFIG_VIDEO_USBTV) += usbtv.o diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c new file mode 100644 index 000000000000..2d8795f683bf --- /dev/null +++ b/drivers/media/usb/usbtv/usbtv-audio.c @@ -0,0 +1,384 @@ +/* + * Fushicai USBTV007 Audio-Video Grabber Driver + * + * Product web site: + * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html + * + * Copyright (c) 2013 Federico Simoncelli + * All rights reserved. + * No physical hardware was harmed running Windows during the + * reverse-engineering activity + * + * 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. The name of the author may not 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"). + */ + +#include +#include +#include +#include + +#include "usbtv.h" + +static struct snd_pcm_hardware snd_usbtv_digital_hw = { + .info = SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .period_bytes_min = 11059, + .period_bytes_max = 13516, + .periods_min = 2, + .periods_max = 98, + .buffer_bytes_max = 62720 * 8, /* value in usbaudio.c */ +}; + +static int snd_usbtv_pcm_open(struct snd_pcm_substream *substream) +{ + struct usbtv *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + chip->snd_substream = substream; + runtime->hw = snd_usbtv_digital_hw; + + return 0; +} + +static int snd_usbtv_pcm_close(struct snd_pcm_substream *substream) +{ + struct usbtv *chip = snd_pcm_substream_chip(substream); + + if (atomic_read(&chip->snd_stream)) { + atomic_set(&chip->snd_stream, 0); + schedule_work(&chip->snd_trigger); + } + + return 0; +} + +static int snd_usbtv_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + int rv; + struct usbtv *chip = snd_pcm_substream_chip(substream); + + rv = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + + if (rv < 0) { + dev_warn(chip->dev, "pcm audio buffer allocation failure %i\n", + rv); + return rv; + } + + return 0; +} + +static int snd_usbtv_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_lib_free_pages(substream); + return 0; +} + +static int snd_usbtv_prepare(struct snd_pcm_substream *substream) +{ + struct usbtv *chip = snd_pcm_substream_chip(substream); + + chip->snd_buffer_pos = 0; + chip->snd_period_pos = 0; + + return 0; +} + +static void usbtv_audio_urb_received(struct urb *urb) +{ + struct usbtv *chip = urb->context; + struct snd_pcm_substream *substream = chip->snd_substream; + struct snd_pcm_runtime *runtime = substream->runtime; + size_t i, frame_bytes, chunk_length, buffer_pos, period_pos; + int period_elapsed; + void *urb_current; + + switch (urb->status) { + case 0: + case -ETIMEDOUT: + break; + case -ENOENT: + case -EPROTO: + case -ECONNRESET: + case -ESHUTDOWN: + return; + default: + dev_warn(chip->dev, "unknown audio urb status %i\n", + urb->status); + } + + if (!atomic_read(&chip->snd_stream)) + return; + + frame_bytes = runtime->frame_bits >> 3; + chunk_length = USBTV_CHUNK / frame_bytes; + + buffer_pos = chip->snd_buffer_pos; + period_pos = chip->snd_period_pos; + period_elapsed = 0; + + for (i = 0; i < urb->actual_length; i += USBTV_CHUNK_SIZE) { + urb_current = urb->transfer_buffer + i + USBTV_AUDIO_HDRSIZE; + + if (buffer_pos + chunk_length >= runtime->buffer_size) { + size_t cnt = (runtime->buffer_size - buffer_pos) * + frame_bytes; + memcpy(runtime->dma_area + buffer_pos * frame_bytes, + urb_current, cnt); + memcpy(runtime->dma_area, urb_current + cnt, + chunk_length * frame_bytes - cnt); + } else { + memcpy(runtime->dma_area + buffer_pos * frame_bytes, + urb_current, chunk_length * frame_bytes); + } + + buffer_pos += chunk_length; + period_pos += chunk_length; + + if (buffer_pos >= runtime->buffer_size) + buffer_pos -= runtime->buffer_size; + + if (period_pos >= runtime->period_size) { + period_pos -= runtime->period_size; + period_elapsed = 1; + } + } + + snd_pcm_stream_lock(substream); + + chip->snd_buffer_pos = buffer_pos; + chip->snd_period_pos = period_pos; + + snd_pcm_stream_unlock(substream); + + if (period_elapsed) + snd_pcm_period_elapsed(substream); + + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int usbtv_audio_start(struct usbtv *chip) +{ + unsigned int pipe; + static const u16 setup[][2] = { + /* These seem to enable the device. */ + { USBTV_BASE + 0x0008, 0x0001 }, + { USBTV_BASE + 0x01d0, 0x00ff }, + { USBTV_BASE + 0x01d9, 0x0002 }, + + { USBTV_BASE + 0x01da, 0x0013 }, + { USBTV_BASE + 0x01db, 0x0012 }, + { USBTV_BASE + 0x01e9, 0x0002 }, + { USBTV_BASE + 0x01ec, 0x006c }, + { USBTV_BASE + 0x0294, 0x0020 }, + { USBTV_BASE + 0x0255, 0x00cf }, + { USBTV_BASE + 0x0256, 0x0020 }, + { USBTV_BASE + 0x01eb, 0x0030 }, + { USBTV_BASE + 0x027d, 0x00a6 }, + { USBTV_BASE + 0x0280, 0x0011 }, + { USBTV_BASE + 0x0281, 0x0040 }, + { USBTV_BASE + 0x0282, 0x0011 }, + { USBTV_BASE + 0x0283, 0x0040 }, + { 0xf891, 0x0010 }, + + /* this sets the input from composite */ + { USBTV_BASE + 0x0284, 0x00aa }, + }; + + chip->snd_bulk_urb = usb_alloc_urb(0, GFP_KERNEL); + if (chip->snd_bulk_urb == NULL) + goto err_alloc_urb; + + pipe = usb_rcvbulkpipe(chip->udev, USBTV_AUDIO_ENDP); + + chip->snd_bulk_urb->transfer_buffer = kzalloc( + USBTV_AUDIO_URBSIZE, GFP_KERNEL); + if (chip->snd_bulk_urb->transfer_buffer == NULL) + goto err_transfer_buffer; + + usb_fill_bulk_urb(chip->snd_bulk_urb, chip->udev, pipe, + chip->snd_bulk_urb->transfer_buffer, USBTV_AUDIO_URBSIZE, + usbtv_audio_urb_received, chip); + + /* starting the stream */ + usbtv_set_regs(chip, setup, ARRAY_SIZE(setup)); + + usb_clear_halt(chip->udev, pipe); + usb_submit_urb(chip->snd_bulk_urb, GFP_ATOMIC); + + return 0; + +err_transfer_buffer: + usb_free_urb(chip->snd_bulk_urb); + chip->snd_bulk_urb = NULL; + +err_alloc_urb: + return -ENOMEM; +} + +static int usbtv_audio_stop(struct usbtv *chip) +{ + static const u16 setup[][2] = { + /* The original windows driver sometimes sends also: + * { USBTV_BASE + 0x00a2, 0x0013 } + * but it seems useless and its real effects are untested at + * the moment. + */ + { USBTV_BASE + 0x027d, 0x0000 }, + { USBTV_BASE + 0x0280, 0x0010 }, + { USBTV_BASE + 0x0282, 0x0010 }, + }; + + if (chip->snd_bulk_urb) { + usb_kill_urb(chip->snd_bulk_urb); + kfree(chip->snd_bulk_urb->transfer_buffer); + usb_free_urb(chip->snd_bulk_urb); + chip->snd_bulk_urb = NULL; + } + + usbtv_set_regs(chip, setup, ARRAY_SIZE(setup)); + + return 0; +} + +void usbtv_audio_suspend(struct usbtv *usbtv) +{ + if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb) + usb_kill_urb(usbtv->snd_bulk_urb); +} + +void usbtv_audio_resume(struct usbtv *usbtv) +{ + if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb) + usb_submit_urb(usbtv->snd_bulk_urb, GFP_ATOMIC); +} + +static void snd_usbtv_trigger(struct work_struct *work) +{ + struct usbtv *chip = container_of(work, struct usbtv, snd_trigger); + + if (atomic_read(&chip->snd_stream)) + usbtv_audio_start(chip); + else + usbtv_audio_stop(chip); +} + +static int snd_usbtv_card_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct usbtv *chip = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + atomic_set(&chip->snd_stream, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + atomic_set(&chip->snd_stream, 0); + break; + default: + return -EINVAL; + } + + schedule_work(&chip->snd_trigger); + + return 0; +} + +static snd_pcm_uframes_t snd_usbtv_pointer(struct snd_pcm_substream *substream) +{ + struct usbtv *chip = snd_pcm_substream_chip(substream); + return chip->snd_buffer_pos; +} + +static struct snd_pcm_ops snd_usbtv_pcm_ops = { + .open = snd_usbtv_pcm_open, + .close = snd_usbtv_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_usbtv_hw_params, + .hw_free = snd_usbtv_hw_free, + .prepare = snd_usbtv_prepare, + .trigger = snd_usbtv_card_trigger, + .pointer = snd_usbtv_pointer, +}; + +int usbtv_audio_init(struct usbtv *usbtv) +{ + int rv; + struct snd_card *card; + struct snd_pcm *pcm; + + INIT_WORK(&usbtv->snd_trigger, snd_usbtv_trigger); + atomic_set(&usbtv->snd_stream, 0); + + rv = snd_card_new(&usbtv->udev->dev, SNDRV_DEFAULT_IDX1, "usbtv", + THIS_MODULE, 0, &card); + if (rv < 0) + return rv; + + strlcpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver)); + strlcpy(card->shortname, "usbtv", sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "USBTV Audio at bus %d device %d", usbtv->udev->bus->busnum, + usbtv->udev->devnum); + + snd_card_set_dev(card, usbtv->dev); + + usbtv->snd = card; + + rv = snd_pcm_new(card, "USBTV Audio", 0, 0, 1, &pcm); + if (rv < 0) + goto err; + + strlcpy(pcm->name, "USBTV Audio Input", sizeof(pcm->name)); + pcm->info_flags = 0; + pcm->private_data = usbtv; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usbtv_pcm_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), USBTV_AUDIO_BUFFER, + USBTV_AUDIO_BUFFER); + + rv = snd_card_register(card); + if (rv) + goto err; + + return 0; + +err: + usbtv->snd = NULL; + snd_card_free(card); + + return rv; +} + +void usbtv_audio_free(struct usbtv *usbtv) +{ + if (usbtv->snd && usbtv->udev) { + snd_card_free(usbtv->snd); + usbtv->snd = NULL; + } +} diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 473fab81b602..bf25ecf143a2 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -1,5 +1,5 @@ /* - * Fushicai USBTV007 Video Grabber Driver + * Fushicai USBTV007 Audio-Video Grabber Driver * * Product web site: * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html @@ -84,12 +84,19 @@ static int usbtv_probe(struct usb_interface *intf, if (ret < 0) goto usbtv_video_fail; + ret = usbtv_audio_init(usbtv); + if (ret < 0) + goto usbtv_audio_fail; + /* for simplicity we exploit the v4l2_device reference counting */ v4l2_device_get(&usbtv->v4l2_dev); - dev_info(dev, "Fushicai USBTV007 Video Grabber\n"); + dev_info(dev, "Fushicai USBTV007 Audio-Video Grabber\n"); return 0; +usbtv_audio_fail: + usbtv_video_free(usbtv); + usbtv_video_fail: usb_set_intfdata(intf, NULL); usb_put_dev(usbtv->udev); @@ -106,6 +113,7 @@ static void usbtv_disconnect(struct usb_interface *intf) if (!usbtv) return; + usbtv_audio_free(usbtv); usbtv_video_free(usbtv); usb_put_dev(usbtv->udev); @@ -122,8 +130,8 @@ static struct usb_device_id usbtv_id_table[] = { }; MODULE_DEVICE_TABLE(usb, usbtv_id_table); -MODULE_AUTHOR("Lubomir Rintel"); -MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver"); +MODULE_AUTHOR("Lubomir Rintel, Federico Simoncelli"); +MODULE_DESCRIPTION("Fushicai USBTV007 Audio-Video Grabber Driver"); MODULE_LICENSE("Dual BSD/GPL"); static struct usb_driver usbtv_usb_driver = { diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 030c5854b4b3..692c7188a8a6 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -1,5 +1,5 @@ /* - * Fushicai USBTV007 Video Grabber Driver + * Fushicai USBTV007 Audio-Video Grabber Driver * * Product web site: * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html @@ -79,7 +79,6 @@ static int usbtv_select_input(struct usbtv *usbtv, int input) { USBTV_BASE + 0x011f, 0x00f2 }, { USBTV_BASE + 0x0127, 0x0060 }, { USBTV_BASE + 0x00ae, 0x0010 }, - { USBTV_BASE + 0x0284, 0x00aa }, { USBTV_BASE + 0x0239, 0x0060 }, }; @@ -88,7 +87,6 @@ static int usbtv_select_input(struct usbtv *usbtv, int input) { USBTV_BASE + 0x011f, 0x00ff }, { USBTV_BASE + 0x0127, 0x0060 }, { USBTV_BASE + 0x00ae, 0x0030 }, - { USBTV_BASE + 0x0284, 0x0088 }, { USBTV_BASE + 0x0239, 0x0060 }, }; @@ -225,7 +223,6 @@ static int usbtv_setup_capture(struct usbtv *usbtv) { USBTV_BASE + 0x0159, 0x0006 }, { USBTV_BASE + 0x015d, 0x0000 }, - { USBTV_BASE + 0x0284, 0x0088 }, { USBTV_BASE + 0x0003, 0x0004 }, { USBTV_BASE + 0x0100, 0x00d3 }, { USBTV_BASE + 0x0115, 0x0015 }, @@ -434,6 +431,8 @@ static int usbtv_start(struct usbtv *usbtv) int i; int ret; + usbtv_audio_suspend(usbtv); + ret = usb_set_interface(usbtv->udev, 0, 0); if (ret < 0) return ret; @@ -446,6 +445,8 @@ static int usbtv_start(struct usbtv *usbtv) if (ret < 0) return ret; + usbtv_audio_resume(usbtv); + for (i = 0; i < USBTV_ISOC_TRANSFERS; i++) { struct urb *ip; diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h index cb1d388cc647..968119581fab 100644 --- a/drivers/media/usb/usbtv/usbtv.h +++ b/drivers/media/usb/usbtv/usbtv.h @@ -1,5 +1,5 @@ /* - * Fushicai USBTV007 Video Grabber Driver + * Fushicai USBTV007 Audio-Video Grabber Driver * * Copyright (c) 2013 Lubomir Rintel * All rights reserved. @@ -28,6 +28,7 @@ /* Hardware. */ #define USBTV_VIDEO_ENDP 0x81 +#define USBTV_AUDIO_ENDP 0x83 #define USBTV_BASE 0xc000 #define USBTV_REQUEST_REG 12 @@ -39,6 +40,10 @@ #define USBTV_CHUNK_SIZE 256 #define USBTV_CHUNK 240 +#define USBTV_AUDIO_URBSIZE 20480 +#define USBTV_AUDIO_HDRSIZE 4 +#define USBTV_AUDIO_BUFFER 65536 + /* Chunk header. */ #define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ == 0x88000000) @@ -91,9 +96,23 @@ struct usbtv { int iso_size; unsigned int sequence; struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS]; + + /* audio */ + struct snd_card *snd; + struct snd_pcm_substream *snd_substream; + atomic_t snd_stream; + struct work_struct snd_trigger; + struct urb *snd_bulk_urb; + size_t snd_buffer_pos; + size_t snd_period_pos; }; int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size); int usbtv_video_init(struct usbtv *usbtv); void usbtv_video_free(struct usbtv *usbtv); + +int usbtv_audio_init(struct usbtv *usbtv); +void usbtv_audio_free(struct usbtv *usbtv); +void usbtv_audio_suspend(struct usbtv *usbtv); +void usbtv_audio_resume(struct usbtv *usbtv); -- GitLab From d4b32646468088323f27a7788ce3b07191015142 Mon Sep 17 00:00:00 2001 From: Vitaly Osipov Date: Thu, 5 Jun 2014 04:07:48 -0300 Subject: [PATCH 0580/5088] [media] staging: omap4iss: copy paste error in iss_get_clocks It makes more sense to return PTR_ERR(iss->iss_ctrlclk) here. The current code looks like an oversight in pasting the block just above this one. Signed-off-by: Vitaly Osipov Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/omap4iss/iss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index d548371db65a..8a23d164e847 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -1014,6 +1014,7 @@ static int iss_get_clocks(struct iss_device *iss) iss->iss_ctrlclk = devm_clk_get(iss->dev, "iss_ctrlclk"); if (IS_ERR(iss->iss_ctrlclk)) { dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n"); + iss_put_clocks(iss); return PTR_ERR(iss->iss_ctrlclk); } -- GitLab From 0d8053f2ace52c816800193d705ea82a2ffd6dc8 Mon Sep 17 00:00:00 2001 From: Ulrich Eckhardt Date: Sat, 26 Jul 2014 14:56:01 -0300 Subject: [PATCH 0581/5088] [media] imon: Define keytables per USB Device Id This patch defines the keytables per USB Device ID. Signed-off-by: Ulrich Eckhardt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 266 ++++++++++++++++++++++++++-------------- 1 file changed, 173 insertions(+), 93 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 7115e68ba697..3fc759537cc6 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -87,6 +87,18 @@ static ssize_t lcd_write(struct file *file, const char __user *buf, /*** G L O B A L S ***/ +struct imon_panel_key_table { + u64 hw_code; + u32 keycode; +}; + +struct imon_usb_dev_descr { + __u16 flags; +#define IMON_NO_FLAGS 0 +#define IMON_NEED_20MS_PKT_DELAY 1 + struct imon_panel_key_table key_table[]; +}; + struct imon_context { struct device *dev; /* Newer devices have two interfaces */ @@ -150,6 +162,8 @@ struct imon_context { struct timer_list ttimer; /* touch screen timer */ int touch_x; /* x coordinate on touchscreen */ int touch_y; /* y coordinate on touchscreen */ + struct imon_usb_dev_descr *dev_descr; /* device description with key + table for front panels */ }; #define TOUCH_TIMEOUT (HZ/30) @@ -186,8 +200,111 @@ enum { IMON_KEY_PANEL = 2, }; -enum { - IMON_NEED_20MS_PKT_DELAY = 1 +static struct usb_class_driver imon_vfd_class = { + .name = DEVICE_NAME, + .fops = &vfd_fops, + .minor_base = DISPLAY_MINOR_BASE, +}; + +static struct usb_class_driver imon_lcd_class = { + .name = DEVICE_NAME, + .fops = &lcd_fops, + .minor_base = DISPLAY_MINOR_BASE, +}; + +/* imon receiver front panel/knob key table */ +static const struct imon_usb_dev_descr imon_default_table = { + .flags = IMON_NO_FLAGS, + .key_table = { + { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ + { 0x000000001200ffeell, KEY_UP }, + { 0x000000001300ffeell, KEY_DOWN }, + { 0x000000001400ffeell, KEY_LEFT }, + { 0x000000001500ffeell, KEY_RIGHT }, + { 0x000000001600ffeell, KEY_ENTER }, + { 0x000000001700ffeell, KEY_ESC }, + { 0x000000001f00ffeell, KEY_AUDIO }, + { 0x000000002000ffeell, KEY_VIDEO }, + { 0x000000002100ffeell, KEY_CAMERA }, + { 0x000000002700ffeell, KEY_DVD }, + { 0x000000002300ffeell, KEY_TV }, + { 0x000000002b00ffeell, KEY_EXIT }, + { 0x000000002c00ffeell, KEY_SELECT }, + { 0x000000002d00ffeell, KEY_MENU }, + { 0x000000000500ffeell, KEY_PREVIOUS }, + { 0x000000000700ffeell, KEY_REWIND }, + { 0x000000000400ffeell, KEY_STOP }, + { 0x000000003c00ffeell, KEY_PLAYPAUSE }, + { 0x000000000800ffeell, KEY_FASTFORWARD }, + { 0x000000000600ffeell, KEY_NEXT }, + { 0x000000010000ffeell, KEY_RIGHT }, + { 0x000001000000ffeell, KEY_LEFT }, + { 0x000000003d00ffeell, KEY_SELECT }, + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000000100ffeell, KEY_MUTE }, + /* 0xffdc iMON MCE VFD */ + { 0x00010000ffffffeell, KEY_VOLUMEUP }, + { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, + { 0x00000001ffffffeell, KEY_MUTE }, + { 0x0000000fffffffeell, KEY_MEDIA }, + { 0x00000012ffffffeell, KEY_UP }, + { 0x00000013ffffffeell, KEY_DOWN }, + { 0x00000014ffffffeell, KEY_LEFT }, + { 0x00000015ffffffeell, KEY_RIGHT }, + { 0x00000016ffffffeell, KEY_ENTER }, + { 0x00000017ffffffeell, KEY_ESC }, + /* iMON Knob values */ + { 0x000100ffffffffeell, KEY_VOLUMEUP }, + { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, + { 0x000008ffffffffeell, KEY_MUTE }, + { 0, KEY_RESERVED }, + } +}; + +static const struct imon_usb_dev_descr imon_OEM_VFD = { + .flags = IMON_NEED_20MS_PKT_DELAY, + .key_table = { + { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ + { 0x000000001200ffeell, KEY_UP }, + { 0x000000001300ffeell, KEY_DOWN }, + { 0x000000001400ffeell, KEY_LEFT }, + { 0x000000001500ffeell, KEY_RIGHT }, + { 0x000000001600ffeell, KEY_ENTER }, + { 0x000000001700ffeell, KEY_ESC }, + { 0x000000001f00ffeell, KEY_AUDIO }, + { 0x000000002b00ffeell, KEY_EXIT }, + { 0x000000002c00ffeell, KEY_SELECT }, + { 0x000000002d00ffeell, KEY_MENU }, + { 0x000000000500ffeell, KEY_PREVIOUS }, + { 0x000000000700ffeell, KEY_REWIND }, + { 0x000000000400ffeell, KEY_STOP }, + { 0x000000003c00ffeell, KEY_PLAYPAUSE }, + { 0x000000000800ffeell, KEY_FASTFORWARD }, + { 0x000000000600ffeell, KEY_NEXT }, + { 0x000000010000ffeell, KEY_RIGHT }, + { 0x000001000000ffeell, KEY_LEFT }, + { 0x000000003d00ffeell, KEY_SELECT }, + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000000100ffeell, KEY_MUTE }, + /* 0xffdc iMON MCE VFD */ + { 0x00010000ffffffeell, KEY_VOLUMEUP }, + { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, + { 0x00000001ffffffeell, KEY_MUTE }, + { 0x0000000fffffffeell, KEY_MEDIA }, + { 0x00000012ffffffeell, KEY_UP }, + { 0x00000013ffffffeell, KEY_DOWN }, + { 0x00000014ffffffeell, KEY_LEFT }, + { 0x00000015ffffffeell, KEY_RIGHT }, + { 0x00000016ffffffeell, KEY_ENTER }, + { 0x00000017ffffffeell, KEY_ESC }, + /* iMON Knob values */ + { 0x000100ffffffffeell, KEY_VOLUMEUP }, + { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, + { 0x000008ffffffffeell, KEY_MUTE }, + { 0, KEY_RESERVED }, + } }; /* @@ -208,7 +325,8 @@ static struct usb_device_id imon_usb_id_table[] = { * SoundGraph iMON PAD (IR & LCD) * SoundGraph iMON Knob (IR only) */ - { USB_DEVICE(0x15c2, 0xffdc) }, + { USB_DEVICE(0x15c2, 0xffdc), + .driver_info = (unsigned long)&imon_default_table }, /* * Newer devices, all driven by the latest iMON Windows driver, full @@ -216,43 +334,62 @@ static struct usb_device_id imon_usb_id_table[] = { * Need user input to fill in details on unknown devices. */ /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */ - { USB_DEVICE(0x15c2, 0x0034) }, + { USB_DEVICE(0x15c2, 0x0034), + .driver_info = (unsigned long)&imon_default_table }, /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ - { USB_DEVICE(0x15c2, 0x0035) }, + { USB_DEVICE(0x15c2, 0x0035), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON OEM VFD (IR & VFD) */ - { USB_DEVICE(0x15c2, 0x0036), .driver_info = IMON_NEED_20MS_PKT_DELAY }, + { USB_DEVICE(0x15c2, 0x0036), + .driver_info = (unsigned long)&imon_OEM_VFD }, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0037) }, + { USB_DEVICE(0x15c2, 0x0037), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON OEM LCD (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0038) }, + { USB_DEVICE(0x15c2, 0x0038), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON UltraBay (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0039) }, + { USB_DEVICE(0x15c2, 0x0039), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003a) }, + { USB_DEVICE(0x15c2, 0x003a), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003b) }, + { USB_DEVICE(0x15c2, 0x003b), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON OEM Inside (IR only) */ - { USB_DEVICE(0x15c2, 0x003c) }, + { USB_DEVICE(0x15c2, 0x003c), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003d) }, + { USB_DEVICE(0x15c2, 0x003d), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003e) }, + { USB_DEVICE(0x15c2, 0x003e), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x003f) }, + { USB_DEVICE(0x15c2, 0x003f), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0040) }, + { USB_DEVICE(0x15c2, 0x0040), + .driver_info = (unsigned long)&imon_default_table}, /* SoundGraph iMON MINI (IR only) */ - { USB_DEVICE(0x15c2, 0x0041) }, + { USB_DEVICE(0x15c2, 0x0041), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station EZ External (IR only) */ - { USB_DEVICE(0x15c2, 0x0042) }, + { USB_DEVICE(0x15c2, 0x0042), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station Basic Internal (IR only) */ - { USB_DEVICE(0x15c2, 0x0043) }, + { USB_DEVICE(0x15c2, 0x0043), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station Elite (IR & VFD) */ - { USB_DEVICE(0x15c2, 0x0044) }, + { USB_DEVICE(0x15c2, 0x0044), + .driver_info = (unsigned long)&imon_default_table}, /* Antec Veris Multimedia Station Premiere (IR & LCD) */ - { USB_DEVICE(0x15c2, 0x0045) }, + { USB_DEVICE(0x15c2, 0x0045), + .driver_info = (unsigned long)&imon_default_table}, /* device specifics unknown */ - { USB_DEVICE(0x15c2, 0x0046) }, + { USB_DEVICE(0x15c2, 0x0046), + .driver_info = (unsigned long)&imon_default_table}, {} }; @@ -266,67 +403,6 @@ static struct usb_driver imon_driver = { .id_table = imon_usb_id_table, }; -static struct usb_class_driver imon_vfd_class = { - .name = DEVICE_NAME, - .fops = &vfd_fops, - .minor_base = DISPLAY_MINOR_BASE, -}; - -static struct usb_class_driver imon_lcd_class = { - .name = DEVICE_NAME, - .fops = &lcd_fops, - .minor_base = DISPLAY_MINOR_BASE, -}; - -/* imon receiver front panel/knob key table */ -static const struct { - u64 hw_code; - u32 keycode; -} imon_panel_key_table[] = { - { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ - { 0x000000001200ffeell, KEY_UP }, - { 0x000000001300ffeell, KEY_DOWN }, - { 0x000000001400ffeell, KEY_LEFT }, - { 0x000000001500ffeell, KEY_RIGHT }, - { 0x000000001600ffeell, KEY_ENTER }, - { 0x000000001700ffeell, KEY_ESC }, - { 0x000000001f00ffeell, KEY_AUDIO }, - { 0x000000002000ffeell, KEY_VIDEO }, - { 0x000000002100ffeell, KEY_CAMERA }, - { 0x000000002700ffeell, KEY_DVD }, - { 0x000000002300ffeell, KEY_TV }, - { 0x000000002b00ffeell, KEY_EXIT }, - { 0x000000002c00ffeell, KEY_SELECT }, - { 0x000000002d00ffeell, KEY_MENU }, - { 0x000000000500ffeell, KEY_PREVIOUS }, - { 0x000000000700ffeell, KEY_REWIND }, - { 0x000000000400ffeell, KEY_STOP }, - { 0x000000003c00ffeell, KEY_PLAYPAUSE }, - { 0x000000000800ffeell, KEY_FASTFORWARD }, - { 0x000000000600ffeell, KEY_NEXT }, - { 0x000000010000ffeell, KEY_RIGHT }, - { 0x000001000000ffeell, KEY_LEFT }, - { 0x000000003d00ffeell, KEY_SELECT }, - { 0x000100000000ffeell, KEY_VOLUMEUP }, - { 0x010000000000ffeell, KEY_VOLUMEDOWN }, - { 0x000000000100ffeell, KEY_MUTE }, - /* 0xffdc iMON MCE VFD */ - { 0x00010000ffffffeell, KEY_VOLUMEUP }, - { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, - { 0x00000001ffffffeell, KEY_MUTE }, - { 0x0000000fffffffeell, KEY_MEDIA }, - { 0x00000012ffffffeell, KEY_UP }, - { 0x00000013ffffffeell, KEY_DOWN }, - { 0x00000014ffffffeell, KEY_LEFT }, - { 0x00000015ffffffeell, KEY_RIGHT }, - { 0x00000016ffffffeell, KEY_ENTER }, - { 0x00000017ffffffeell, KEY_ESC }, - /* iMON Knob values */ - { 0x000100ffffffffeell, KEY_VOLUMEUP }, - { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, - { 0x000008ffffffffeell, KEY_MUTE }, -}; - /* to prevent races between open() and disconnect(), probing, etc */ static DEFINE_MUTEX(driver_lock); @@ -1210,18 +1286,19 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode) return keycode; } -static u32 imon_panel_key_lookup(u64 code) +static u32 imon_panel_key_lookup(struct imon_context *ictx, u64 code) { int i; u32 keycode = KEY_RESERVED; + struct imon_panel_key_table *key_table = ictx->dev_descr->key_table; - for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { - if (imon_panel_key_table[i].hw_code == (code | 0xffee)) { - keycode = imon_panel_key_table[i].keycode; + for (i = 0; key_table[i].hw_code != 0; i++) { + if (key_table[i].hw_code == (code | 0xffee)) { + keycode = key_table[i].keycode; break; } } - + ictx->release_code = false; return keycode; } @@ -1511,7 +1588,7 @@ static void imon_incoming_packet(struct imon_context *ictx, if (len == 8 && buf[7] == 0xee) { scancode = be64_to_cpu(*((u64 *)buf)); ktype = IMON_KEY_PANEL; - kc = imon_panel_key_lookup(scancode); + kc = imon_panel_key_lookup(ictx, scancode); } else { scancode = be32_to_cpu(*((u32 *)buf)); if (ictx->rc_type == RC_BIT_RC6_MCE) { @@ -1908,6 +1985,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) static struct input_dev *imon_init_idev(struct imon_context *ictx) { + struct imon_panel_key_table *key_table = ictx->dev_descr->key_table; struct input_dev *idev; int ret, i; @@ -1933,8 +2011,8 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) BIT_MASK(REL_WHEEL); /* panel and/or knob code support */ - for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { - u32 kc = imon_panel_key_table[i].keycode; + for (i = 0; key_table[i].hw_code != 0; i++) { + u32 kc = key_table[i].keycode; __set_bit(kc, idev->keybit); } @@ -2135,9 +2213,11 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf, ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); + /* save drive info for later accessing the panel/knob key table */ + ictx->dev_descr = (struct imon_usb_dev_descr *)id->driver_info; /* default send_packet delay is 5ms but some devices need more */ - ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ? - 20 : 5; + ictx->send_packet_delay = ictx->dev_descr->flags & + IMON_NEED_20MS_PKT_DELAY ? 20 : 5; ret = -ENODEV; iface_desc = intf->cur_altsetting; -- GitLab From 7b5fc0714976aec5db5c4f8c66f12b23f5049b97 Mon Sep 17 00:00:00 2001 From: Ulrich Eckhardt Date: Sat, 26 Jul 2014 14:59:07 -0300 Subject: [PATCH 0582/5088] [media] imon: Add internal key table for 15c2:0034 Add the key table for the Thermaltake DH-102 to the USB-Id 15c2:0034. Signed-off-by: Ulrich Eckhardt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 3fc759537cc6..c91e9709b47e 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -307,6 +307,27 @@ static const struct imon_usb_dev_descr imon_OEM_VFD = { } }; +/* imon receiver front panel/knob key table for DH102*/ +static const struct imon_usb_dev_descr imon_DH102 = { + .flags = IMON_NO_FLAGS, + .key_table = { + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000010000ffeell, KEY_MUTE }, + { 0x0000000f0000ffeell, KEY_MEDIA }, + { 0x000000120000ffeell, KEY_UP }, + { 0x000000130000ffeell, KEY_DOWN }, + { 0x000000140000ffeell, KEY_LEFT }, + { 0x000000150000ffeell, KEY_RIGHT }, + { 0x000000160000ffeell, KEY_ENTER }, + { 0x000000170000ffeell, KEY_ESC }, + { 0x0000002b0000ffeell, KEY_EXIT }, + { 0x0000002c0000ffeell, KEY_SELECT }, + { 0x0000002d0000ffeell, KEY_MENU }, + { 0, KEY_RESERVED } + } +}; + /* * USB Device ID for iMON USB Control Boards * @@ -335,7 +356,7 @@ static struct usb_device_id imon_usb_id_table[] = { */ /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */ { USB_DEVICE(0x15c2, 0x0034), - .driver_info = (unsigned long)&imon_default_table }, + .driver_info = (unsigned long)&imon_DH102 }, /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ { USB_DEVICE(0x15c2, 0x0035), .driver_info = (unsigned long)&imon_default_table}, -- GitLab From 6ddc2be511a76e6c3f689f46155cb0f4c8f5876e Mon Sep 17 00:00:00 2001 From: Ulrich Eckhardt Date: Sat, 26 Jul 2014 15:01:12 -0300 Subject: [PATCH 0583/5088] [media] imon: Fix not working front panel Make the front panel buttons working after another button on the remote was pressed. Signed-off-by: Ulrich Eckhardt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index c91e9709b47e..3d8f515be3c1 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1610,6 +1610,7 @@ static void imon_incoming_packet(struct imon_context *ictx, scancode = be64_to_cpu(*((u64 *)buf)); ktype = IMON_KEY_PANEL; kc = imon_panel_key_lookup(ictx, scancode); + ictx->release_code = false; } else { scancode = be32_to_cpu(*((u32 *)buf)); if (ictx->rc_type == RC_BIT_RC6_MCE) { -- GitLab From 6e533c01a89fbb8b1a5c58808540e798e2dad645 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Aug 2014 03:52:08 -0300 Subject: [PATCH 0584/5088] [media] v4l: Event documentation fixes Constify event type constants and correct motion detection event number (it's 6, not 5). Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-dqevent.xml | 7 ++++--- Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml index cb7732582f03..b036f8963353 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml @@ -76,21 +76,22 @@ &v4l2-event-vsync; vsync - Event data for event V4L2_EVENT_VSYNC. + Event data for event V4L2_EVENT_VSYNC. &v4l2-event-ctrl; ctrl - Event data for event V4L2_EVENT_CTRL. + Event data for event V4L2_EVENT_CTRL. &v4l2-event-frame-sync; frame_sync - Event data for event V4L2_EVENT_FRAME_SYNC. + Event data for event + V4L2_EVENT_FRAME_SYNC. diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml index 9f6095608837..d7c9365ecdbe 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml @@ -176,7 +176,7 @@ V4L2_EVENT_MOTION_DET - 5 + 6 Triggered whenever the motion detection state for one or more of the regions changes. This event has a &v4l2-event-motion-det; associated with it. -- GitLab From 4721b3eb662ca5ea60a636f0f190f2fd2ac5df14 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 02:58:40 -0300 Subject: [PATCH 0585/5088] [media] ov7670: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Acked-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7670.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index cdd7c1b7259b..dd3db2458a4f 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -19,6 +19,7 @@ #include #include #include +#include #include MODULE_AUTHOR("Jonathan Corbet "); @@ -29,19 +30,6 @@ static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -/* - * Basic window sizes. These probably belong somewhere more globally - * useful. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 -#define CIF_WIDTH 352 -#define CIF_HEIGHT 288 -#define QCIF_WIDTH 176 -#define QCIF_HEIGHT 144 - /* * The 7670 sits on i2c with ID 0x42 */ -- GitLab From 37096b476b45e60b2b264d0b517089b47cb9374b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 02:59:44 -0300 Subject: [PATCH 0586/5088] [media] vs6624: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/vs6624.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 23f4f65fccd7..373f2df52492 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -30,22 +30,10 @@ #include #include #include +#include #include "vs6624_regs.h" -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 -#define QQVGA_WIDTH 160 -#define QQVGA_HEIGHT 120 -#define CIF_WIDTH 352 -#define CIF_HEIGHT 288 -#define QCIF_WIDTH 176 -#define QCIF_HEIGHT 144 -#define QQCIF_WIDTH 88 -#define QQCIF_HEIGHT 72 - #define MAX_FRAME_RATE 30 struct vs6624 { -- GitLab From 665152a4fb9f60df1c28cee8ab2634a6533edb9c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 03:00:44 -0300 Subject: [PATCH 0587/5088] [media] soc_camera: mt9t112: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/mt9t112.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 46f431a13782..996d7b4007a5 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -29,6 +29,7 @@ #include #include #include +#include /* you can check PLL/clock info */ /* #define EXT_CLOCK 24000000 */ @@ -42,9 +43,6 @@ #define MAX_WIDTH 2048 #define MAX_HEIGHT 1536 -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 - /* * macro of read/write */ -- GitLab From a14e55190b8ac8305870ed9f7b5e1375ed870a34 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 03:01:39 -0300 Subject: [PATCH 0588/5088] [media] soc_camera: ov772x: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/ov772x.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 7f2b3c8926af..970a04e1e56e 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -29,6 +29,7 @@ #include #include #include +#include /* * register offset @@ -360,10 +361,6 @@ #define SCAL0_ACTRL 0x08 /* Auto scaling factor control */ #define SCAL1_2_ACTRL 0x04 /* Auto scaling factor control */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 #define OV772X_MAX_WIDTH VGA_WIDTH #define OV772X_MAX_HEIGHT VGA_HEIGHT -- GitLab From 91ba0e59babdb3c7aca836a65f1095b3eaff7b06 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 8 Aug 2014 10:32:56 -0300 Subject: [PATCH 0589/5088] [media] tda7432: Fix setting TDA7432_MUTE bit for TDA7432_RF register Fix a copy-paste bug when converting to the control framework. Fixes: commit 5d478e0de871 ("[media] tda7432: convert to the control framework") Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda7432.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index 72af644fa051..cf93021a6500 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -293,7 +293,7 @@ static int tda7432_s_ctrl(struct v4l2_ctrl *ctrl) if (t->mute->val) { lf |= TDA7432_MUTE; lr |= TDA7432_MUTE; - lf |= TDA7432_MUTE; + rf |= TDA7432_MUTE; rr |= TDA7432_MUTE; } /* Mute & update balance*/ -- GitLab From 7c5a62e1eee1f59a5d2c25bbd28f0929811ffefa Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 03:19:20 -0300 Subject: [PATCH 0590/5088] [media] sh_veu: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_veu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 8dc279d4d561..be3b3bc71a0f 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #define VEU_STR 0x00 /* start register */ @@ -135,9 +136,6 @@ enum sh_veu_fmt_idx { SH_VEU_FMT_RGB24, }; -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 - #define DEFAULT_IN_WIDTH VGA_WIDTH #define DEFAULT_IN_HEIGHT VGA_HEIGHT #define DEFAULT_IN_FMTIDX SH_VEU_FMT_NV12 -- GitLab From c0d04f4026c305eadeac6cfdffdbac5fcdf9bc60 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Aug 2014 03:20:01 -0300 Subject: [PATCH 0591/5088] [media] via-camera: Include media/v4l2-image-sizes.h So we can remove the same defines in the driver code. Signed-off-by: Axel Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/via-camera.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index b4f9d03636e3..2ac870438493 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -48,14 +49,6 @@ MODULE_PARM_DESC(override_serial, "the XO 1.5 serial port is enabled. Set this option " "to force-enable the camera."); -/* - * Basic window sizes. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QCIF_WIDTH 176 -#define QCIF_HEIGHT 144 - /* * The structure describing our camera. */ -- GitLab From 627530c32a43283474e9dd3e954519410ffa033a Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sat, 9 Aug 2014 06:37:20 -0300 Subject: [PATCH 0592/5088] [media] em28xx-v4l: give back all active video buffers to the vb2 core properly on streaming stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a new video frame is started, the driver takes the next video buffer from the list of active buffers and moves it to dev->usb_ctl.vid_buf / dev->usb_ctl.vbi_buf for further processing. On streaming stop we currently only give back the pending buffers from the list but not the ones which are currently processed. This causes the following warning from the vb2 core since kernel 3.15: ... ------------[ cut here ]------------ WARNING: CPU: 1 PID: 2284 at drivers/media/v4l2-core/videobuf2-core.c:2115 __vb2_queue_cancel+0xed/0x150 [videobuf2_core]() [...] Call Trace: [] dump_stack+0x48/0x69 [] warn_slowpath_common+0x79/0x90 [] ? __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] ? __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] warn_slowpath_null+0x1d/0x20 [] __vb2_queue_cancel+0xed/0x150 [videobuf2_core] [] vb2_internal_streamoff+0x35/0x90 [videobuf2_core] [] vb2_streamoff+0x35/0x60 [videobuf2_core] [] vb2_ioctl_streamoff+0x37/0x40 [videobuf2_core] [] v4l_streamoff+0x15/0x20 [videodev] [] __video_do_ioctl+0x23d/0x2d0 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] video_usercopy+0x203/0x5a0 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] ? fsnotify+0x1e7/0x2b0 [] video_ioctl2+0x12/0x20 [videodev] [] ? video_ioctl2+0x20/0x20 [videodev] [] v4l2_ioctl+0xee/0x130 [videodev] [] ? v4l2_open+0xf0/0xf0 [videodev] [] do_vfs_ioctl+0x2e2/0x4d0 [] ? vfs_write+0x13c/0x1c0 [] ? vfs_writev+0x2f/0x50 [] SyS_ioctl+0x58/0x80 [] sysenter_do_call+0x12/0x12 ---[ end trace 5545f934409f13f4 ]--- ... Many thanks to Hans Verkuil, whose recently added check in the vb2 core unveiled this long standing issue and who has investigated it further. Cc: Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 90dec2955f1c..9db219d513db 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -994,13 +994,16 @@ static void em28xx_stop_streaming(struct vb2_queue *vq) } spin_lock_irqsave(&dev->slock, flags); + if (dev->usb_ctl.vid_buf != NULL) { + vb2_buffer_done(&dev->usb_ctl.vid_buf->vb, VB2_BUF_STATE_ERROR); + dev->usb_ctl.vid_buf = NULL; + } while (!list_empty(&vidq->active)) { struct em28xx_buffer *buf; buf = list_entry(vidq->active.next, struct em28xx_buffer, list); list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - dev->usb_ctl.vid_buf = NULL; spin_unlock_irqrestore(&dev->slock, flags); } @@ -1021,13 +1024,16 @@ void em28xx_stop_vbi_streaming(struct vb2_queue *vq) } spin_lock_irqsave(&dev->slock, flags); + if (dev->usb_ctl.vbi_buf != NULL) { + vb2_buffer_done(&dev->usb_ctl.vbi_buf->vb, VB2_BUF_STATE_ERROR); + dev->usb_ctl.vbi_buf = NULL; + } while (!list_empty(&vbiq->active)) { struct em28xx_buffer *buf; buf = list_entry(vbiq->active.next, struct em28xx_buffer, list); list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - dev->usb_ctl.vbi_buf = NULL; spin_unlock_irqrestore(&dev->slock, flags); } -- GitLab From 662c97cf8f9e9d67d45d0a9f0c1565a1ede364c2 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sat, 9 Aug 2014 06:37:21 -0300 Subject: [PATCH 0593/5088] [media] em28xx-v4l: fix video buffer field order reporting in progressive mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The correct field order in progressive mode is V4L2_FIELD_NONE, not V4L2_FIELD_INTERLACED. Cc: Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 9db219d513db..f6cf99fa30b2 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -435,7 +435,10 @@ static inline void finish_buffer(struct em28xx *dev, em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field); buf->vb.v4l2_buf.sequence = dev->v4l2->field_count++; - buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; + if (dev->v4l2->progressive) + buf->vb.v4l2_buf.field = V4L2_FIELD_NONE; + else + buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); -- GitLab From 66cae53024c4b73d40b4e78c557a73e082522aed Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 13 Aug 2014 15:52:39 -0300 Subject: [PATCH 0594/5088] [media] media: fix au0828 dvb suspend/resume to call dvb_frontend_suspend/resume au0828 doesn't resume correctly and TV tuning fails with xc_set_signal_source(0) failed message. Change au0828 dvb suspend and resume interfaces to suspend and resume frontend during suspend and resume respectively. dvb_frontend_suspend() suspends tuner and fe using tuner and fe ops. dvb_frontend_resume() resumes fe and tuner using fe and tuner ops ini before waking up the frontend. With this change HVR950Q suspend and resume work when system gets suspended when digital function is tuned to a channel and with active TV stream, and after resume it went right back to active TV stream. Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-dvb.c | 47 +++++++++++++++------------ 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 821f86e92cde..4bd9d687d2d6 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -620,34 +620,39 @@ int au0828_dvb_register(struct au0828_dev *dev) void au0828_dvb_suspend(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; + int rc; - if (dvb->frontend && dev->urb_streaming) { - pr_info("stopping DVB\n"); - - cancel_work_sync(&dev->restart_streaming); - - /* Stop transport */ - mutex_lock(&dvb->lock); - stop_urb_transfer(dev); - au0828_stop_transport(dev, 1); - mutex_unlock(&dvb->lock); - dev->need_urb_start = 1; + if (dvb->frontend) { + if (dev->urb_streaming) { + cancel_work_sync(&dev->restart_streaming); + /* Stop transport */ + mutex_lock(&dvb->lock); + stop_urb_transfer(dev); + au0828_stop_transport(dev, 1); + mutex_unlock(&dvb->lock); + dev->need_urb_start = 1; + } + /* suspend frontend - does tuner and fe to sleep */ + rc = dvb_frontend_suspend(dvb->frontend); + pr_info("au0828_dvb_suspend(): Suspending DVB fe %d\n", rc); } } void au0828_dvb_resume(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; + int rc; - if (dvb->frontend && dev->need_urb_start) { - pr_info("resuming DVB\n"); - - au0828_set_frontend(dvb->frontend); - - /* Start transport */ - mutex_lock(&dvb->lock); - au0828_start_transport(dev); - start_urb_transfer(dev); - mutex_unlock(&dvb->lock); + if (dvb->frontend) { + /* resume frontend - does fe and tuner init */ + rc = dvb_frontend_resume(dvb->frontend); + pr_info("au0828_dvb_resume(): Resuming DVB fe %d\n", rc); + if (dev->need_urb_start) { + /* Start transport */ + mutex_lock(&dvb->lock); + au0828_start_transport(dev); + start_urb_transfer(dev); + mutex_unlock(&dvb->lock); + } } } -- GitLab From 85c1abcb5251673d18325576f4923bb78af479de Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 15 Aug 2014 16:16:46 -0300 Subject: [PATCH 0595/5088] [media] usbtv: Make it dependent on ALSA Now that alsa code is part of the driver, it can be compiled only if alsa is enabled. drivers/built-in.o: In function `snd_usbtv_hw_free': >> usbtv-audio.c:(.text+0x21eb55): undefined reference to `snd_pcm_lib_free_pages' drivers/built-in.o: In function `snd_usbtv_hw_params': >> usbtv-audio.c:(.text+0x21eb72): undefined reference to `snd_pcm_lib_malloc_pages' drivers/built-in.o: In function `usbtv_audio_urb_received': >> usbtv-audio.c:(.text+0x21ed66): undefined reference to `snd_pcm_link_rwlock' >> usbtv-audio.c:(.text+0x21ed9f): undefined reference to `snd_pcm_link_rwlock' >> usbtv-audio.c:(.text+0x21edf5): undefined reference to `snd_pcm_period_elapsed' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f00a): undefined reference to `snd_card_new' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f0a2): undefined reference to `snd_pcm_new' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f0e5): undefined reference to `snd_pcm_set_ops' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f103): undefined reference to `snd_pcm_lib_preallocate_pages_for_all' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f10c): undefined reference to `snd_card_register' drivers/built-in.o: In function `usbtv_audio_init': >> (.text+0x21f12a): undefined reference to `snd_card_free' drivers/built-in.o: In function `usbtv_audio_free': >> (.text+0x21f15c): undefined reference to `snd_card_free' >> drivers/built-in.o:(.data+0x43250): undefined reference to `snd_pcm_lib_ioctl' Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig index 7c5b86006ee6..b833c5b9094e 100644 --- a/drivers/media/usb/usbtv/Kconfig +++ b/drivers/media/usb/usbtv/Kconfig @@ -1,6 +1,7 @@ config VIDEO_USBTV tristate "USBTV007 video capture support" - depends on VIDEO_V4L2 + depends on VIDEO_V4L2 && SND + select SND_PCM select VIDEOBUF2_VMALLOC ---help--- -- GitLab From b250392f7b5062cf026b1423e27265e278fd6b30 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Aug 2014 21:15:53 -0300 Subject: [PATCH 0596/5088] [media] media: ttpci: fix av7110 build to be compatible with CONFIG_INPUT_EVDEV Fix build when CONFIG_INPUT_EVDEV=m and DVB_AV7110=y. Only build av7110_ir.c when CONFIG_INPUT_EVDEV is compatible with CONFIG_DVB_AV7110. Fixes these build errors: drivers/built-in.o: In function `input_sync': av7110_ir.c:(.text+0x1223ac): undefined reference to `input_event' drivers/built-in.o: In function `av7110_emit_key': av7110_ir.c:(.text+0x12247c): undefined reference to `input_event' av7110_ir.c:(.text+0x122495): undefined reference to `input_event' av7110_ir.c:(.text+0x122569): undefined reference to `input_event' av7110_ir.c:(.text+0x1225a7): undefined reference to `input_event' drivers/built-in.o:av7110_ir.c:(.text+0x122629): more undefined references to `input_event' follow drivers/built-in.o: In function `av7110_ir_init': (.text+0x1227e4): undefined reference to `input_allocate_device' drivers/built-in.o: In function `av7110_ir_init': (.text+0x12298f): undefined reference to `input_register_device' drivers/built-in.o: In function `av7110_ir_init': (.text+0x12299e): undefined reference to `input_free_device' drivers/built-in.o: In function `av7110_ir_exit': (.text+0x122a94): undefined reference to `input_unregister_device' drivers/built-in.o: In function `av7110_detach': av7110.c:(.text+0x228d4a): undefined reference to `av7110_ir_exit' drivers/built-in.o: In function `arm_thread': av7110.c:(.text+0x22a404): undefined reference to `av7110_check_ir_config' av7110.c:(.text+0x22a626): undefined reference to `av7110_check_ir_config' drivers/built-in.o: In function `av7110_attach': av7110.c:(.text+0x22b08c): undefined reference to `av7110_ir_init' Signed-off-by: Randy Dunlap Reported-by: Randy Dunlap Reported-by: Jim Davis Reported-by: Fengguang Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/Kconfig | 4 ++++ drivers/media/pci/ttpci/Makefile | 2 +- drivers/media/pci/ttpci/av7110.c | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig index 0dcb8cd77676..7b83151ed6c4 100644 --- a/drivers/media/pci/ttpci/Kconfig +++ b/drivers/media/pci/ttpci/Kconfig @@ -1,8 +1,12 @@ +config DVB_AV7110_IR + bool + config DVB_AV7110 tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C select TTPCI_EEPROM select VIDEO_SAA7146_VV + select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110 depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile index 98905963ff08..49f71b1eaf14 100644 --- a/drivers/media/pci/ttpci/Makefile +++ b/drivers/media/pci/ttpci/Makefile @@ -5,7 +5,7 @@ dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o -ifdef CONFIG_INPUT_EVDEV +ifdef CONFIG_DVB_AV7110_IR dvb-ttpci-objs += av7110_ir.o endif diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index f38329d29daa..c1f0617a6973 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -235,7 +235,7 @@ static void recover_arm(struct av7110 *av7110) restart_feeds(av7110); -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_check_ir_config(av7110, true); #endif } @@ -268,7 +268,7 @@ static int arm_thread(void *data) if (!av7110->arm_ready) continue; -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_check_ir_config(av7110, false); #endif @@ -2725,7 +2725,7 @@ static int av7110_attach(struct saa7146_dev* dev, mutex_init(&av7110->ioctl_mutex); -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_ir_init(av7110); #endif printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); @@ -2768,7 +2768,7 @@ static int av7110_detach(struct saa7146_dev* saa) struct av7110 *av7110 = saa->ext_priv; dprintk(4, "%p\n", av7110); -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_ir_exit(av7110); #endif if (budgetpatch || av7110->full_ts) { -- GitLab From c40724d3f38122b8ae06367a425a63c24988c10f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 4 Jun 2014 00:52:30 -0700 Subject: [PATCH 0597/5088] kconfig: lxdialog: fix spelling Signed-off-by: Brian Norris Cc: "Yann E. MORIN" Signed-off-by: Michal Marek --- scripts/kconfig/lxdialog/dialog.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index b4343d384926..fcffd5b41fb0 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h @@ -170,7 +170,7 @@ char item_tag(void); /* item list manipulation for lxdialog use */ #define MAXITEMSTR 200 struct dialog_item { - char str[MAXITEMSTR]; /* promtp displayed */ + char str[MAXITEMSTR]; /* prompt displayed */ char tag; void *data; /* pointer to menu item - used by menubox+checklist */ int selected; /* Set to 1 by dialog_*() function if selected. */ -- GitLab From 7285996aa0006d671bb01f0d35991d254b2b2b01 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 4 Jun 2014 00:52:31 -0700 Subject: [PATCH 0598/5088] kconfig: nconfig: fix multi-byte UTF handling Currently, Kconfig descriptions that use multi-byte UTF-8 characters (such as MTD_NAND_CAFE) will have their menu entries dropped from the 'make nconfig' ncurses menu, and all subsequent entries in the same window will be omitted. This seems to be due to the ncurses 'menu' library, which does not traditionally handle UTF-8 >8-bit characters properly. The ncursesw library ('w' is for "wide") is written to handle these UTF-8 characters, and is practically a drop-in replacement at the source level. Use it by default, if available. Link: https://bugzilla.kernel.org/show_bug.cgi?id=43067 Signed-off-by: Brian Norris Cc: "Yann E. MORIN" Cc: Martin Walch Acked-by: Sam Ravnborg Signed-off-by: Michal Marek --- scripts/kconfig/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index e7bf38e92007..c05938555225 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -191,7 +191,8 @@ HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC)) HOSTLOADLIBES_nconf = $(shell \ - pkg-config --libs menu panel ncurses 2>/dev/null \ + pkg-config --libs menuw panelw ncursesw 2>/dev/null \ + || pkg-config --libs menu panel ncurses 2>/dev/null \ || echo "-lmenu -lpanel -lncurses" ) $(obj)/qconf.o: $(obj)/.tmp_qtcheck -- GitLab From d44bc558297222d9a621fff2eca3f880e91c49f7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 15 Aug 2014 22:08:36 +0300 Subject: [PATCH 0599/5088] perf tests: Add a test for tracking with sched_switch Add a test that checks that sched_switch events and tracking events can be recorded for a workload using the evsel->system_wide and evsel->tracking flags (respectively) with other events sometimes enabled or disabled. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1408129739-17368-2-git-send-email-adrian.hunter@intel.com [ Fix build on fedora14 by using a designated initializer for the sched_switch variable ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 1 + tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/switch-tracking.c | 572 +++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + 4 files changed, 578 insertions(+) create mode 100644 tools/perf/tests/switch-tracking.c diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 1ea31e275b4d..95e832b1bc3c 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -425,6 +425,7 @@ endif endif LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o +LIB_OBJS += $(OUTPUT)tests/switch-tracking.o BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o BUILTIN_OBJS += $(OUTPUT)builtin-bench.o diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 99481361b19f..6a4145e5ad2c 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -153,6 +153,10 @@ static struct test { .desc = "Test cumulation of child hist entries", .func = test__hists_cumulate, }, + { + .desc = "Test tracking with sched_switch", + .func = test__switch_tracking, + }, { .func = NULL, }, diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c new file mode 100644 index 000000000000..cc68648c7c55 --- /dev/null +++ b/tools/perf/tests/switch-tracking.c @@ -0,0 +1,572 @@ +#include +#include +#include +#include + +#include "parse-events.h" +#include "evlist.h" +#include "evsel.h" +#include "thread_map.h" +#include "cpumap.h" +#include "tests.h" + +static int spin_sleep(void) +{ + struct timeval start, now, diff, maxtime; + struct timespec ts; + int err, i; + + maxtime.tv_sec = 0; + maxtime.tv_usec = 50000; + + err = gettimeofday(&start, NULL); + if (err) + return err; + + /* Spin for 50ms */ + while (1) { + for (i = 0; i < 1000; i++) + barrier(); + + err = gettimeofday(&now, NULL); + if (err) + return err; + + timersub(&now, &start, &diff); + if (timercmp(&diff, &maxtime, > /* For checkpatch */)) + break; + } + + ts.tv_nsec = 50 * 1000 * 1000; + ts.tv_sec = 0; + + /* Sleep for 50ms */ + err = nanosleep(&ts, NULL); + if (err == EINTR) + err = 0; + + return err; +} + +struct switch_tracking { + struct perf_evsel *switch_evsel; + struct perf_evsel *cycles_evsel; + pid_t *tids; + int nr_tids; + int comm_seen[4]; + int cycles_before_comm_1; + int cycles_between_comm_2_and_comm_3; + int cycles_after_comm_4; +}; + +static int check_comm(struct switch_tracking *switch_tracking, + union perf_event *event, const char *comm, int nr) +{ + if (event->header.type == PERF_RECORD_COMM && + (pid_t)event->comm.pid == getpid() && + (pid_t)event->comm.tid == getpid() && + strcmp(event->comm.comm, comm) == 0) { + if (switch_tracking->comm_seen[nr]) { + pr_debug("Duplicate comm event\n"); + return -1; + } + switch_tracking->comm_seen[nr] = 1; + pr_debug3("comm event: %s nr: %d\n", event->comm.comm, nr); + return 1; + } + return 0; +} + +static int check_cpu(struct switch_tracking *switch_tracking, int cpu) +{ + int i, nr = cpu + 1; + + if (cpu < 0) + return -1; + + if (!switch_tracking->tids) { + switch_tracking->tids = calloc(nr, sizeof(pid_t)); + if (!switch_tracking->tids) + return -1; + for (i = 0; i < nr; i++) + switch_tracking->tids[i] = -1; + switch_tracking->nr_tids = nr; + return 0; + } + + if (cpu >= switch_tracking->nr_tids) { + void *addr; + + addr = realloc(switch_tracking->tids, nr * sizeof(pid_t)); + if (!addr) + return -1; + switch_tracking->tids = addr; + for (i = switch_tracking->nr_tids; i < nr; i++) + switch_tracking->tids[i] = -1; + switch_tracking->nr_tids = nr; + return 0; + } + + return 0; +} + +static int process_sample_event(struct perf_evlist *evlist, + union perf_event *event, + struct switch_tracking *switch_tracking) +{ + struct perf_sample sample; + struct perf_evsel *evsel; + pid_t next_tid, prev_tid; + int cpu, err; + + if (perf_evlist__parse_sample(evlist, event, &sample)) { + pr_debug("perf_evlist__parse_sample failed\n"); + return -1; + } + + evsel = perf_evlist__id2evsel(evlist, sample.id); + if (evsel == switch_tracking->switch_evsel) { + next_tid = perf_evsel__intval(evsel, &sample, "next_pid"); + prev_tid = perf_evsel__intval(evsel, &sample, "prev_pid"); + cpu = sample.cpu; + pr_debug3("sched_switch: cpu: %d prev_tid %d next_tid %d\n", + cpu, prev_tid, next_tid); + err = check_cpu(switch_tracking, cpu); + if (err) + return err; + /* + * Check for no missing sched_switch events i.e. that the + * evsel->system_wide flag has worked. + */ + if (switch_tracking->tids[cpu] != -1 && + switch_tracking->tids[cpu] != prev_tid) { + pr_debug("Missing sched_switch events\n"); + return -1; + } + switch_tracking->tids[cpu] = next_tid; + } + + if (evsel == switch_tracking->cycles_evsel) { + pr_debug3("cycles event\n"); + if (!switch_tracking->comm_seen[0]) + switch_tracking->cycles_before_comm_1 = 1; + if (switch_tracking->comm_seen[1] && + !switch_tracking->comm_seen[2]) + switch_tracking->cycles_between_comm_2_and_comm_3 = 1; + if (switch_tracking->comm_seen[3]) + switch_tracking->cycles_after_comm_4 = 1; + } + + return 0; +} + +static int process_event(struct perf_evlist *evlist, union perf_event *event, + struct switch_tracking *switch_tracking) +{ + if (event->header.type == PERF_RECORD_SAMPLE) + return process_sample_event(evlist, event, switch_tracking); + + if (event->header.type == PERF_RECORD_COMM) { + int err, done = 0; + + err = check_comm(switch_tracking, event, "Test COMM 1", 0); + if (err < 0) + return -1; + done += err; + err = check_comm(switch_tracking, event, "Test COMM 2", 1); + if (err < 0) + return -1; + done += err; + err = check_comm(switch_tracking, event, "Test COMM 3", 2); + if (err < 0) + return -1; + done += err; + err = check_comm(switch_tracking, event, "Test COMM 4", 3); + if (err < 0) + return -1; + done += err; + if (done != 1) { + pr_debug("Unexpected comm event\n"); + return -1; + } + } + + return 0; +} + +struct event_node { + struct list_head list; + union perf_event *event; + u64 event_time; +}; + +static int add_event(struct perf_evlist *evlist, struct list_head *events, + union perf_event *event) +{ + struct perf_sample sample; + struct event_node *node; + + node = malloc(sizeof(struct event_node)); + if (!node) { + pr_debug("malloc failed\n"); + return -1; + } + node->event = event; + list_add(&node->list, events); + + if (perf_evlist__parse_sample(evlist, event, &sample)) { + pr_debug("perf_evlist__parse_sample failed\n"); + return -1; + } + + if (!sample.time) { + pr_debug("event with no time\n"); + return -1; + } + + node->event_time = sample.time; + + return 0; +} + +static void free_event_nodes(struct list_head *events) +{ + struct event_node *node; + + while (!list_empty(events)) { + node = list_entry(events->next, struct event_node, list); + list_del(&node->list); + free(node); + } +} + +static int compar(const void *a, const void *b) +{ + const struct event_node *nodea = a; + const struct event_node *nodeb = b; + s64 cmp = nodea->event_time - nodeb->event_time; + + return cmp; +} + +static int process_events(struct perf_evlist *evlist, + struct switch_tracking *switch_tracking) +{ + union perf_event *event; + unsigned pos, cnt = 0; + LIST_HEAD(events); + struct event_node *events_array, *node; + int i, ret; + + for (i = 0; i < evlist->nr_mmaps; i++) { + while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { + cnt += 1; + ret = add_event(evlist, &events, event); + perf_evlist__mmap_consume(evlist, i); + if (ret < 0) + goto out_free_nodes; + } + } + + events_array = calloc(cnt, sizeof(struct event_node)); + if (!events_array) { + pr_debug("calloc failed\n"); + ret = -1; + goto out_free_nodes; + } + + pos = 0; + list_for_each_entry(node, &events, list) + events_array[pos++] = *node; + + qsort(events_array, cnt, sizeof(struct event_node), compar); + + for (pos = 0; pos < cnt; pos++) { + ret = process_event(evlist, events_array[pos].event, + switch_tracking); + if (ret < 0) + goto out_free; + } + + ret = 0; +out_free: + pr_debug("%u events recorded\n", cnt); + free(events_array); +out_free_nodes: + free_event_nodes(&events); + return ret; +} + +/** + * test__switch_tracking - test using sched_switch and tracking events. + * + * This function implements a test that checks that sched_switch events and + * tracking events can be recorded for a workload (current process) using the + * evsel->system_wide and evsel->tracking flags (respectively) with other events + * sometimes enabled or disabled. + */ +int test__switch_tracking(void) +{ + const char *sched_switch = "sched:sched_switch"; + struct switch_tracking switch_tracking = { .tids = NULL, }; + struct record_opts opts = { + .mmap_pages = UINT_MAX, + .user_freq = UINT_MAX, + .user_interval = ULLONG_MAX, + .freq = 4000, + .target = { + .uses_mmap = true, + }, + }; + struct thread_map *threads = NULL; + struct cpu_map *cpus = NULL; + struct perf_evlist *evlist = NULL; + struct perf_evsel *evsel, *cpu_clocks_evsel, *cycles_evsel; + struct perf_evsel *switch_evsel, *tracking_evsel; + const char *comm; + int err = -1; + + threads = thread_map__new(-1, getpid(), UINT_MAX); + if (!threads) { + pr_debug("thread_map__new failed!\n"); + goto out_err; + } + + cpus = cpu_map__new(NULL); + if (!cpus) { + pr_debug("cpu_map__new failed!\n"); + goto out_err; + } + + evlist = perf_evlist__new(); + if (!evlist) { + pr_debug("perf_evlist__new failed!\n"); + goto out_err; + } + + perf_evlist__set_maps(evlist, cpus, threads); + + /* First event */ + err = parse_events(evlist, "cpu-clock:u"); + if (err) { + pr_debug("Failed to parse event dummy:u\n"); + goto out_err; + } + + cpu_clocks_evsel = perf_evlist__last(evlist); + + /* Second event */ + err = parse_events(evlist, "cycles:u"); + if (err) { + pr_debug("Failed to parse event cycles:u\n"); + goto out_err; + } + + cycles_evsel = perf_evlist__last(evlist); + + /* Third event */ + if (!perf_evlist__can_select_event(evlist, sched_switch)) { + fprintf(stderr, " (no sched_switch)"); + err = 0; + goto out; + } + + err = parse_events(evlist, sched_switch); + if (err) { + pr_debug("Failed to parse event %s\n", sched_switch); + goto out_err; + } + + switch_evsel = perf_evlist__last(evlist); + + perf_evsel__set_sample_bit(switch_evsel, CPU); + perf_evsel__set_sample_bit(switch_evsel, TIME); + + switch_evsel->system_wide = true; + switch_evsel->no_aux_samples = true; + switch_evsel->immediate = true; + + /* Test moving an event to the front */ + if (cycles_evsel == perf_evlist__first(evlist)) { + pr_debug("cycles event already at front"); + goto out_err; + } + perf_evlist__to_front(evlist, cycles_evsel); + if (cycles_evsel != perf_evlist__first(evlist)) { + pr_debug("Failed to move cycles event to front"); + goto out_err; + } + + perf_evsel__set_sample_bit(cycles_evsel, CPU); + perf_evsel__set_sample_bit(cycles_evsel, TIME); + + /* Fourth event */ + err = parse_events(evlist, "dummy:u"); + if (err) { + pr_debug("Failed to parse event dummy:u\n"); + goto out_err; + } + + tracking_evsel = perf_evlist__last(evlist); + + perf_evlist__set_tracking_event(evlist, tracking_evsel); + + tracking_evsel->attr.freq = 0; + tracking_evsel->attr.sample_period = 1; + + perf_evsel__set_sample_bit(tracking_evsel, TIME); + + /* Config events */ + perf_evlist__config(evlist, &opts); + + /* Check moved event is still at the front */ + if (cycles_evsel != perf_evlist__first(evlist)) { + pr_debug("Front event no longer at front"); + goto out_err; + } + + /* Check tracking event is tracking */ + if (!tracking_evsel->attr.mmap || !tracking_evsel->attr.comm) { + pr_debug("Tracking event not tracking\n"); + goto out_err; + } + + /* Check non-tracking events are not tracking */ + evlist__for_each(evlist, evsel) { + if (evsel != tracking_evsel) { + if (evsel->attr.mmap || evsel->attr.comm) { + pr_debug("Non-tracking event is tracking\n"); + goto out_err; + } + } + } + + if (perf_evlist__open(evlist) < 0) { + fprintf(stderr, " (not supported)"); + err = 0; + goto out; + } + + err = perf_evlist__mmap(evlist, UINT_MAX, false); + if (err) { + pr_debug("perf_evlist__mmap failed!\n"); + goto out_err; + } + + perf_evlist__enable(evlist); + + err = perf_evlist__disable_event(evlist, cpu_clocks_evsel); + if (err) { + pr_debug("perf_evlist__disable_event failed!\n"); + goto out_err; + } + + err = spin_sleep(); + if (err) { + pr_debug("spin_sleep failed!\n"); + goto out_err; + } + + comm = "Test COMM 1"; + err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); + if (err) { + pr_debug("PR_SET_NAME failed!\n"); + goto out_err; + } + + err = perf_evlist__disable_event(evlist, cycles_evsel); + if (err) { + pr_debug("perf_evlist__disable_event failed!\n"); + goto out_err; + } + + comm = "Test COMM 2"; + err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); + if (err) { + pr_debug("PR_SET_NAME failed!\n"); + goto out_err; + } + + err = spin_sleep(); + if (err) { + pr_debug("spin_sleep failed!\n"); + goto out_err; + } + + comm = "Test COMM 3"; + err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); + if (err) { + pr_debug("PR_SET_NAME failed!\n"); + goto out_err; + } + + err = perf_evlist__enable_event(evlist, cycles_evsel); + if (err) { + pr_debug("perf_evlist__disable_event failed!\n"); + goto out_err; + } + + comm = "Test COMM 4"; + err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); + if (err) { + pr_debug("PR_SET_NAME failed!\n"); + goto out_err; + } + + err = spin_sleep(); + if (err) { + pr_debug("spin_sleep failed!\n"); + goto out_err; + } + + perf_evlist__disable(evlist); + + switch_tracking.switch_evsel = switch_evsel; + switch_tracking.cycles_evsel = cycles_evsel; + + err = process_events(evlist, &switch_tracking); + + zfree(&switch_tracking.tids); + + if (err) + goto out_err; + + /* Check all 4 comm events were seen i.e. that evsel->tracking works */ + if (!switch_tracking.comm_seen[0] || !switch_tracking.comm_seen[1] || + !switch_tracking.comm_seen[2] || !switch_tracking.comm_seen[3]) { + pr_debug("Missing comm events\n"); + goto out_err; + } + + /* Check cycles event got enabled */ + if (!switch_tracking.cycles_before_comm_1) { + pr_debug("Missing cycles events\n"); + goto out_err; + } + + /* Check cycles event got disabled */ + if (switch_tracking.cycles_between_comm_2_and_comm_3) { + pr_debug("cycles events even though event was disabled\n"); + goto out_err; + } + + /* Check cycles event got enabled again */ + if (!switch_tracking.cycles_after_comm_4) { + pr_debug("Missing cycles events\n"); + goto out_err; + } +out: + if (evlist) { + perf_evlist__disable(evlist); + perf_evlist__delete(evlist); + } else { + cpu_map__delete(cpus); + thread_map__delete(threads); + } + + return err; + +out_err: + err = -1; + goto out; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index ed64790a395f..be8be10e3957 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -48,6 +48,7 @@ int test__mmap_thread_lookup(void); int test__thread_mg_share(void); int test__hists_output(void); int test__hists_cumulate(void); +int test__switch_tracking(void); #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) #ifdef HAVE_DWARF_UNWIND_SUPPORT -- GitLab From d445dd2a78eed884adf3b3426b078fe69d2516d8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 15 Aug 2014 22:08:37 +0300 Subject: [PATCH 0600/5088] perf scripting: Add 'flush' callback to scripting API In order to defer some output via the scripting API, there needs to be a callback after session processing but before the session is deleted. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1408129739-17368-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 13 +++++++++++++ .../perf/util/scripting-engines/trace-event-perl.c | 6 ++++++ .../util/scripting-engines/trace-event-python.c | 6 ++++++ tools/perf/util/trace-event-scripting.c | 7 +++++++ tools/perf/util/trace-event.h | 1 + 5 files changed, 33 insertions(+) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index c1b7029884b1..02dce9295e2c 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -485,6 +485,11 @@ static int default_start_script(const char *script __maybe_unused, return 0; } +static int default_flush_script(void) +{ + return 0; +} + static int default_stop_script(void) { return 0; @@ -498,6 +503,7 @@ static int default_generate_script(struct pevent *pevent __maybe_unused, static struct scripting_ops default_scripting_ops = { .start_script = default_start_script, + .flush_script = default_flush_script, .stop_script = default_stop_script, .process_event = process_event, .generate_script = default_generate_script, @@ -513,6 +519,11 @@ static void setup_scripting(void) scripting_ops = &default_scripting_ops; } +static int flush_scripting(void) +{ + return scripting_ops->flush_script(); +} + static int cleanup_scripting(void) { pr_debug("\nperf script stopped\n"); @@ -1813,6 +1824,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) err = __cmd_script(&script); + flush_scripting(); + out_delete: perf_session__delete(session); diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index b2dba9c0a3a1..0a01bac4ce02 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -432,6 +432,11 @@ static int perl_start_script(const char *script, int argc, const char **argv) return err; } +static int perl_flush_script(void) +{ + return 0; +} + /* * Stop trace script */ @@ -633,6 +638,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) struct scripting_ops perl_scripting_ops = { .name = "Perl", .start_script = perl_start_script, + .flush_script = perl_flush_script, .stop_script = perl_stop_script, .process_event = perl_process_event, .generate_script = perl_generate_script, diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 26e5f14239ed..56ba07cce549 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -639,6 +639,11 @@ static int python_start_script(const char *script, int argc, const char **argv) return err; } +static int python_flush_script(void) +{ + return 0; +} + /* * Stop trace script */ @@ -823,6 +828,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) struct scripting_ops python_scripting_ops = { .name = "Python", .start_script = python_start_script, + .flush_script = python_flush_script, .stop_script = python_stop_script, .process_event = python_process_event, .generate_script = python_generate_script, diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 57aaccc1692e..5c9bdd1591a9 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -30,6 +30,11 @@ struct scripting_context *scripting_context; +static int flush_script_unsupported(void) +{ + return 0; +} + static int stop_script_unsupported(void) { return 0; @@ -74,6 +79,7 @@ static int python_generate_script_unsupported(struct pevent *pevent struct scripting_ops python_scripting_unsupported_ops = { .name = "Python", .start_script = python_start_script_unsupported, + .flush_script = flush_script_unsupported, .stop_script = stop_script_unsupported, .process_event = process_event_unsupported, .generate_script = python_generate_script_unsupported, @@ -137,6 +143,7 @@ static int perl_generate_script_unsupported(struct pevent *pevent struct scripting_ops perl_scripting_unsupported_ops = { .name = "Perl", .start_script = perl_start_script_unsupported, + .flush_script = flush_script_unsupported, .stop_script = stop_script_unsupported, .process_event = process_event_unsupported, .generate_script = perl_generate_script_unsupported, diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 7b6d68688327..52aaa19e1eb1 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -64,6 +64,7 @@ struct perf_session; struct scripting_ops { const char *name; int (*start_script) (const char *script, int argc, const char **argv); + int (*flush_script) (void); int (*stop_script) (void); void (*process_event) (union perf_event *event, struct perf_sample *sample, -- GitLab From 4b99375b38fa137f501cfa60b70e3f0a9da39c93 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 15 Aug 2014 22:08:38 +0300 Subject: [PATCH 0601/5088] perf machine: Rename machine__get_kernel_start_addr() method Rename machine__get_kernel_start_addr() to machine__get_running_kernel_start() so that a new function, with a similar name to the original name, can be added that gets the kernel start address from the kernel map. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1408129739-17368-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index b093b93607fb..37f8dc557ec0 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -593,8 +593,8 @@ const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; * Returns the name of the start symbol in *symbol_name. Pass in NULL as * symbol_name if it's not that important. */ -static u64 machine__get_kernel_start_addr(struct machine *machine, - const char **symbol_name) +static u64 machine__get_running_kernel_start(struct machine *machine, + const char **symbol_name) { char filename[PATH_MAX]; int i; @@ -621,7 +621,7 @@ static u64 machine__get_kernel_start_addr(struct machine *machine, int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) { enum map_type type; - u64 start = machine__get_kernel_start_addr(machine, NULL); + u64 start = machine__get_running_kernel_start(machine, NULL); for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; @@ -940,7 +940,7 @@ int machine__create_kernel_maps(struct machine *machine) { struct dso *kernel = machine__get_kernel(machine); const char *name; - u64 addr = machine__get_kernel_start_addr(machine, &name); + u64 addr = machine__get_running_kernel_start(machine, &name); if (!addr) return -1; -- GitLab From fbe2af45f6bd27ee69fd775303c936c3af4a4807 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 15 Aug 2014 22:08:39 +0300 Subject: [PATCH 0602/5088] perf tools: Add machine__kernel_ip() Add a function to determine if an address is in the kernel. This is based on the kernel function kernel_ip(). Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1408129739-17368-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 6 +++--- tools/perf/util/machine.c | 23 +++++++++++++++++++++++ tools/perf/util/machine.h | 17 +++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 1398c83d896d..ed558191c0b3 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -784,9 +784,9 @@ void thread__find_addr_map(struct thread *thread, * "[vdso]" dso, but for now lets use the old trick of looking * in the whole kernel symbol list. */ - if ((long long)al->addr < 0 && - cpumode == PERF_RECORD_MISC_USER && - machine && mg != &machine->kmaps) { + if (cpumode == PERF_RECORD_MISC_USER && machine && + mg != &machine->kmaps && + machine__kernel_ip(machine, al->addr)) { mg = &machine->kmaps; load_map = true; goto try_again; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 37f8dc557ec0..e00daf0d2bde 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -32,6 +32,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->symbol_filter = NULL; machine->id_hdr_size = 0; machine->comm_exec = false; + machine->kernel_start = 0; machine->root_dir = strdup(root_dir); if (machine->root_dir == NULL) @@ -1559,3 +1560,25 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, return 0; } + +int machine__get_kernel_start(struct machine *machine) +{ + struct map *map = machine__kernel_map(machine, MAP__FUNCTION); + int err = 0; + + /* + * The only addresses above 2^63 are kernel addresses of a 64-bit + * kernel. Note that addresses are unsigned so that on a 32-bit system + * all addresses including kernel addresses are less than 2^32. In + * that case (32-bit system), if the kernel mapping is unknown, all + * addresses will be assumed to be in user space - see + * machine__kernel_ip(). + */ + machine->kernel_start = 1ULL << 63; + if (map) { + err = map__load(map, machine->symbol_filter); + if (map->start) + machine->kernel_start = map->start; + } + return err; +} diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 61216e028319..6a6bcc1cff54 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -36,6 +36,7 @@ struct machine { struct list_head kernel_dsos; struct map_groups kmaps; struct map *vmlinux_maps[MAP__NR_TYPES]; + u64 kernel_start; symbol_filter_t symbol_filter; pid_t *current_tid; }; @@ -46,6 +47,22 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type) return machine->vmlinux_maps[type]; } +int machine__get_kernel_start(struct machine *machine); + +static inline u64 machine__kernel_start(struct machine *machine) +{ + if (!machine->kernel_start) + machine__get_kernel_start(machine); + return machine->kernel_start; +} + +static inline bool machine__kernel_ip(struct machine *machine, u64 ip) +{ + u64 kernel_start = machine__kernel_start(machine); + + return ip >= kernel_start; +} + struct thread *machine__find_thread(struct machine *machine, pid_t pid, pid_t tid); struct comm *machine__thread_exec_comm(struct machine *machine, -- GitLab From c09a7e755c025558cb882fa20a5f30da738536fa Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 21 Aug 2014 10:15:45 +0900 Subject: [PATCH 0603/5088] perf hists browser: Cleanup callchain print functions The hist_browser__show_callchain() and friends don't need to be that complex. They're splitted in 3 pieces - one for traversing top-level tree, other one for special casing first chains in the top-level entries, and last one for recursive traversing inner trees. It led to code duplication and unnecessary complexity IMHO. Simplify the function and consolidate the logic into a single function - it can recursively call itself. A little difference in printing callchains in top-level tree can be handled with a small change. It should have no functional change. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1408583746-5540-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 112 +++++++++------------------------ 1 file changed, 29 insertions(+), 83 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index d42d8a8f3810..519353d9f5fb 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -502,23 +502,16 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser, #define LEVEL_OFFSET_STEP 3 -static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser, - struct callchain_node *chain_node, - u64 total, int level, - unsigned short row, - off_t *row_offset, - bool *is_current_entry) +static int hist_browser__show_callchain(struct hist_browser *browser, + struct rb_root *root, int level, + unsigned short row, off_t *row_offset, + u64 total, bool *is_current_entry) { struct rb_node *node; int first_row = row, offset = level * LEVEL_OFFSET_STEP; u64 new_total; - if (callchain_param.mode == CHAIN_GRAPH_REL) - new_total = chain_node->children_hit; - else - new_total = total; - - node = rb_first(&chain_node->rb_root); + node = rb_first(root); while (node) { struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); struct rb_node *next = rb_next(node); @@ -535,7 +528,7 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse if (first) first = false; - else + else if (level > 1) extra_offset = LEVEL_OFFSET_STEP; folded_sign = callchain_list__folded(chain); @@ -547,8 +540,9 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse alloc_str = NULL; str = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso); - if (was_first) { - double percent = cumul * 100.0 / new_total; + + if (was_first && level > 1) { + double percent = cumul * 100.0 / total; if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) str = "Not enough memory!"; @@ -571,78 +565,23 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse if (folded_sign == '-') { const int new_level = level + (extra_offset ? 2 : 1); - row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total, - new_level, row, row_offset, - is_current_entry); - } - if (row == browser->b.rows) - goto out; - node = next; - } -out: - return row - first_row; -} - -static int hist_browser__show_callchain_node(struct hist_browser *browser, - struct callchain_node *node, - int level, unsigned short row, - off_t *row_offset, - bool *is_current_entry) -{ - struct callchain_list *chain; - int first_row = row; - int offset = level * LEVEL_OFFSET_STEP; - char folded_sign = ' '; - - list_for_each_entry(chain, &node->val, list) { - char bf[1024], *s; - folded_sign = callchain_list__folded(chain); + if (callchain_param.mode == CHAIN_GRAPH_REL) + new_total = child->children_hit; + else + new_total = total; - if (*row_offset != 0) { - --*row_offset; - continue; + row += hist_browser__show_callchain(browser, &child->rb_root, + new_level, + row, row_offset, + new_total, + is_current_entry); } - - s = callchain_list__sym_name(chain, bf, sizeof(bf), - browser->show_dso); - hist_browser__show_callchain_entry(browser, chain, row, - offset, folded_sign, s, - is_current_entry); - - if (++row == browser->b.rows) - goto out; - } - - if (folded_sign == '-') - row += hist_browser__show_callchain_node_rb_tree(browser, node, - browser->hists->stats.total_period, - level + 1, row, - row_offset, - is_current_entry); -out: - return row - first_row; -} - -static int hist_browser__show_callchain(struct hist_browser *browser, - struct rb_root *chain, - int level, unsigned short row, - off_t *row_offset, - bool *is_current_entry) -{ - struct rb_node *nd; - int first_row = row; - - for (nd = rb_first(chain); nd; nd = rb_next(nd)) { - struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); - - row += hist_browser__show_callchain_node(browser, node, level, - row, row_offset, - is_current_entry); if (row == browser->b.rows) break; + node = next; } - +out: return row - first_row; } @@ -817,9 +756,16 @@ static int hist_browser__show_entry(struct hist_browser *browser, --row_offset; if (folded_sign == '-' && row != browser->b.rows) { - printed += hist_browser__show_callchain(browser, &entry->sorted_chain, + u64 total = hists__total_period(entry->hists); + + if (symbol_conf.cumulate_callchain) + total = entry->stat_acc->period; + + printed += hist_browser__show_callchain(browser, + &entry->sorted_chain, 1, row, &row_offset, - ¤t_entry); + total, ¤t_entry); + if (current_entry) browser->he_selection = entry; } -- GitLab From 06b2afc0b9a26e7673856a24ab57bfb307dad394 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Wed, 20 Aug 2014 23:25:11 -0400 Subject: [PATCH 0604/5088] perf machine: Fallback to MAP__FUNCTION if daddr maps are NULL As we run "perf c2c" on more applications, we noticed we're missing significant samples from a common customer's application. Looking at the /proc//maps file for the app, we see "rwxs" and "rwxp" permissions on many of the shared memory & heap regions, and on all the thread stacks. Because those regions have the "x" bit set, perf marks them with a MAP_FUNCTION type. Hence ip_resolve_data() never finds load or store events coming from them. We fixed this by re-calling thread__find_addr_location with MAP__FUNCTION in the case where map is NULL as a last ditch effort to map the sample before giving up and dropping it. Reported-by: Joe Mario Tested-by: Joe Mario Signed-off-by: Don Zickus Acked-by: Jiri Olsa Cc: Jiri Olsa Cc: Joe Mario Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1408591511-57884-1-git-send-email-dzickus@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index e00daf0d2bde..b2ec38bf211e 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1314,6 +1314,16 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread, thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al); + if (al.map == NULL) { + /* + * some shared data regions have execute bit set which puts + * their mapping in the MAP__FUNCTION type array. + * Check there as a fallback option before dropping the sample. + */ + thread__find_addr_location(thread, machine, m, MAP__FUNCTION, addr, + &al); + } + ams->addr = addr; ams->al_addr = al.addr; ams->sym = al.sym; -- GitLab From b5e995e671d8e4d7a75b339ce78ecc586014b0eb Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 12 Jun 2014 16:24:41 +0530 Subject: [PATCH 0605/5088] nohz: Fix spurious periodic tick behaviour in low-res dynticks mode When we reach the end of the tick handler, we unconditionally reschedule the next tick to the next jiffy. Then on irq exit, the nohz code overrides that setting if needed and defers the next tick as far away in the future as possible. Now in the best dynticks case, when we actually don't need any tick in the future (ie: expires == KTIME_MAX), low-res and high-res behave differently. What we want in this case is to cancel the next tick programmed by the previous one. That's what we do in high-res mode. OTOH we lack a low-res mode equivalent of hrtimer_cancel() so we simply don't do anything in this case and the next tick remains scheduled to jiffies + 1. As a result, in low-res mode, when the dynticks code determines that no tick is needed in the future, we can recursively get a spurious tick every jiffy because then the next tick is always reprogrammed from the tick handler and is never cancelled. And this can happen indefinetly until some subsystem actually needs a precise tick in the future and only then we eventually overwrite the previous tick handler setting to defer the next tick. We are fixing this by introducing the ONESHOT_STOPPED mode which will let us pause a clockevent when no further interrupt is needed. Meanwhile we can't expect all drivers to support this new mode. So lets reduce much of the symptoms by skipping the nohz-blind tick rescheduling from the tick-handler when the CPU is in dynticks mode. That tick rescheduling wrongly assumed periodicity and the low-res dynticks code can't cancel such decision. This breaks the recursive (and thus the worst) part of the problem. In the worst case now, we'll get only one extra tick due to uncancelled tick scheduled before we entered dynticks mode. This also removes a needless clockevent write on idle ticks. Since those clock write are usually considered to be slow, it's a general win. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Cc: Thomas Gleixner Signed-off-by: Frederic Weisbecker --- kernel/time/tick-sched.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 99aa6ee3908f..153870a91350 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -968,6 +968,10 @@ static void tick_nohz_handler(struct clock_event_device *dev) tick_sched_do_timer(now); tick_sched_handle(ts, regs); + /* No need to reprogram if we are running tickless */ + if (unlikely(ts->tick_stopped)) + return; + while (tick_nohz_reprogram(ts, now)) { now = ktime_get(); tick_do_update_jiffies64(now); -- GitLab From 2a16fc93d2c9568e16d45db77c7b5f15e1921cf1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 12 Jun 2014 16:24:41 +0530 Subject: [PATCH 0606/5088] nohz: Avoid tick's double reprogramming in highres mode In highres mode, the tick reschedules itself unconditionally to the next jiffies. However while this clock reprogramming is relevant when the tick is in periodic mode, it's not that interesting when we run in dynticks mode because irq exit is likely going to overwrite the next tick to some randomly deferred future. So lets just get rid of this tick self rescheduling in dynticks mode. This way we can avoid some clockevents double write in favourable scenarios like when we stop the tick completely in idle while no other hrtimer is pending. Suggested-by: Frederic Weisbecker Signed-off-by: Viresh Kumar Cc: Thomas Gleixner Signed-off-by: Frederic Weisbecker --- kernel/time/tick-sched.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 153870a91350..cc0a5b6f741b 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -1099,6 +1099,10 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) if (regs) tick_sched_handle(ts, regs); + /* No need to reprogram if we are in idle or full dynticks mode */ + if (unlikely(ts->tick_stopped)) + return HRTIMER_NORESTART; + hrtimer_forward(timer, now, tick_period); return HRTIMER_RESTART; -- GitLab From c28135481428d0674fcc1da0740ed3f4343df5b2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 22 Aug 2014 22:39:37 +0200 Subject: [PATCH 0607/5088] drm/i915: Update DRIVER_DATE to 20140822 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 d4d2abbb8e6c..d309725a7d7b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -54,7 +54,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20140808" +#define DRIVER_DATE "20140822" enum pipe { INVALID_PIPE = -1, -- GitLab From a18a32ce22d8b0e3174c0633fa61e46aac39e81e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 23 Aug 2014 11:05:21 +0200 Subject: [PATCH 0608/5088] ASoC: ac97-codec: Remove ASoC level IO support This driver doesn't use any ASoC level IO nor does it register any controls or DAPM elements that require it. This means it can safely be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ac97.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index e889e1b84192..bd9b1839c8b0 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -69,19 +69,6 @@ static struct snd_soc_dai_driver ac97_dai = { .ops = &ac97_dai_ops, }; -static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return soc_ac97_ops->read(codec->ac97, reg); -} - -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - soc_ac97_ops->write(codec->ac97, reg, val); - return 0; -} - static int ac97_soc_probe(struct snd_soc_codec *codec) { struct snd_ac97_bus *ac97_bus; @@ -122,8 +109,6 @@ static int ac97_soc_resume(struct snd_soc_codec *codec) #endif static struct snd_soc_codec_driver soc_codec_dev_ac97 = { - .write = ac97_write, - .read = ac97_read, .probe = ac97_soc_probe, .suspend = ac97_soc_suspend, .resume = ac97_soc_resume, -- GitLab From ca99140a63b7326ee9a38f64c326317f2c63b594 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 23 Aug 2014 14:46:10 +0400 Subject: [PATCH 0609/5088] pata_of_platform: Remove "electra-ide" quirk "electra-ide" is not used anywhere in the kernel and could be represented in devicetree in a normal way. This patch removes specific quirk for "electra-ide". Signed-off-by: Alexander Shiyan Signed-off-by: Tejun Heo --- drivers/ata/pata_of_platform.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index a7e95a54c782..6af1c9b9a464 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c @@ -35,20 +35,11 @@ static int pata_of_platform_probe(struct platform_device *ofdev) return -EINVAL; } - if (of_device_is_compatible(dn, "electra-ide")) { - /* Altstatus is really at offset 0x3f6 from the primary window - * on electra-ide. Adjust ctl_res and io_res accordingly. - */ - ctl_res = io_res; - ctl_res.start = ctl_res.start+0x3f6; - io_res.end = ctl_res.start-1; - } else { - ret = of_address_to_resource(dn, 1, &ctl_res); - if (ret) { - dev_err(&ofdev->dev, "can't get CTL address from " - "device tree\n"); - return -EINVAL; - } + ret = of_address_to_resource(dn, 1, &ctl_res); + if (ret) { + dev_err(&ofdev->dev, "can't get CTL address from " + "device tree\n"); + return -EINVAL; } irq_res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0); @@ -79,8 +70,7 @@ static int pata_of_platform_probe(struct platform_device *ofdev) static struct of_device_id pata_of_platform_match[] = { { .compatible = "ata-generic", }, - { .compatible = "electra-ide", }, - {}, + { }, }; MODULE_DEVICE_TABLE(of, pata_of_platform_match); -- GitLab From 53f3cc46336b9e514c98556b4a009a69ed808d3b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 23 Aug 2014 14:45:47 +0400 Subject: [PATCH 0610/5088] pata_platform: Remove useless irq_flags field IRQ flags can be obtained from resource structure, there are no need to use additional field in the platform_data to store these values. This patch removes this field and convert existing users of this driver to use IRQ flags from the resources. Signed-off-by: Alexander Shiyan Signed-off-by: Tejun Heo --- arch/blackfin/mach-bf537/boards/cm_bf537e.c | 3 +-- arch/blackfin/mach-bf537/boards/cm_bf537u.c | 3 +-- arch/blackfin/mach-bf537/boards/stamp.c | 3 +-- arch/blackfin/mach-bf537/boards/tcm_bf537.c | 3 +-- arch/blackfin/mach-bf561/boards/cm_bf561.c | 3 +-- drivers/ata/pata_of_platform.c | 2 -- drivers/ata/pata_platform.c | 4 +--- include/linux/ata_platform.h | 5 ----- 8 files changed, 6 insertions(+), 20 deletions(-) diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537e.c b/arch/blackfin/mach-bf537/boards/cm_bf537e.c index 1e7290ef3525..1e1014df5e9e 100644 --- a/arch/blackfin/mach-bf537/boards/cm_bf537e.c +++ b/arch/blackfin/mach-bf537/boards/cm_bf537e.c @@ -733,7 +733,6 @@ static struct platform_device bfin_mac_device = { static struct pata_platform_info bfin_pata_platform_data = { .ioport_shift = 2, - .irq_type = IRQF_TRIGGER_HIGH, }; static struct resource bfin_pata_resources[] = { @@ -750,7 +749,7 @@ static struct resource bfin_pata_resources[] = { { .start = PATA_INT, .end = PATA_INT, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537u.c b/arch/blackfin/mach-bf537/boards/cm_bf537u.c index c7495dc74690..d056db9e5592 100644 --- a/arch/blackfin/mach-bf537/boards/cm_bf537u.c +++ b/arch/blackfin/mach-bf537/boards/cm_bf537u.c @@ -587,7 +587,6 @@ static struct platform_device bfin_mac_device = { static struct pata_platform_info bfin_pata_platform_data = { .ioport_shift = 2, - .irq_type = IRQF_TRIGGER_HIGH, }; static struct resource bfin_pata_resources[] = { @@ -604,7 +603,7 @@ static struct resource bfin_pata_resources[] = { { .start = PATA_INT, .end = PATA_INT, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index de19b8a56007..88a19fc9844d 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -2462,7 +2462,6 @@ static struct platform_device bfin_sport0_device = { #define PATA_INT IRQ_PF5 static struct pata_platform_info bfin_pata_platform_data = { .ioport_shift = 1, - .irq_flags = IRQF_TRIGGER_HIGH, }; static struct resource bfin_pata_resources[] = { @@ -2479,7 +2478,7 @@ static struct resource bfin_pata_resources[] = { { .start = PATA_INT, .end = PATA_INT, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; #elif defined(CF_IDE_NAND_CARD_USE_CF_IN_COMMON_MEMORY_MODE) diff --git a/arch/blackfin/mach-bf537/boards/tcm_bf537.c b/arch/blackfin/mach-bf537/boards/tcm_bf537.c index 6b988ad653d8..ed309c9a62b6 100644 --- a/arch/blackfin/mach-bf537/boards/tcm_bf537.c +++ b/arch/blackfin/mach-bf537/boards/tcm_bf537.c @@ -589,7 +589,6 @@ static struct platform_device bfin_mac_device = { static struct pata_platform_info bfin_pata_platform_data = { .ioport_shift = 2, - .irq_type = IRQF_TRIGGER_HIGH, }; static struct resource bfin_pata_resources[] = { @@ -606,7 +605,7 @@ static struct resource bfin_pata_resources[] = { { .start = PATA_INT, .end = PATA_INT, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c index e862f7823e68..c6db52ba3a06 100644 --- a/arch/blackfin/mach-bf561/boards/cm_bf561.c +++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c @@ -354,7 +354,6 @@ static struct platform_device bfin_sir0_device = { static struct pata_platform_info bfin_pata_platform_data = { .ioport_shift = 2, - .irq_type = IRQF_TRIGGER_HIGH, }; static struct resource bfin_pata_resources[] = { @@ -371,7 +370,7 @@ static struct resource bfin_pata_resources[] = { { .start = PATA_INT, .end = PATA_INT, - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL, }, }; diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index 6af1c9b9a464..64965398914a 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c @@ -43,8 +43,6 @@ static int pata_of_platform_probe(struct platform_device *ofdev) } irq_res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0); - if (irq_res) - irq_res->flags = 0; prop = of_get_property(dn, "reg-shift", NULL); if (prop) diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index a5579b55e332..f8cff3e247c5 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -118,7 +118,7 @@ int __pata_platform_probe(struct device *dev, struct resource *io_res, */ if (irq_res && irq_res->start > 0) { irq = irq_res->start; - irq_flags = irq_res->flags; + irq_flags = irq_res->flags & IRQF_TRIGGER_MASK; } /* @@ -213,8 +213,6 @@ static int pata_platform_probe(struct platform_device *pdev) * And the IRQ */ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (irq_res) - irq_res->flags = pp_info ? pp_info->irq_flags : 0; return __pata_platform_probe(&pdev->dev, io_res, ctl_res, irq_res, pp_info ? pp_info->ioport_shift : 0, diff --git a/include/linux/ata_platform.h b/include/linux/ata_platform.h index b9fde17f767c..5c618a084225 100644 --- a/include/linux/ata_platform.h +++ b/include/linux/ata_platform.h @@ -8,11 +8,6 @@ struct pata_platform_info { * spacing used by ata_std_ports(). */ unsigned int ioport_shift; - /* - * Indicate platform specific irq types and initial - * IRQ flags when call request_irq() - */ - unsigned int irq_flags; }; extern int __pata_platform_probe(struct device *dev, -- GitLab From 61b67684c4a4d04b30d9ed67aa2eadfa0089c590 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 13 Aug 2014 19:39:56 +0200 Subject: [PATCH 0611/5088] perf: Fix perf_poll to return proper POLLHUP value Currently perf_poll returns POLL_HUP in case of error, which is wrong, because poll syscall expects POLLHUP. The POLL_HUP is meant to be used for SIGIO state. Signed-off-by: Jiri Olsa Acked-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20140811120102.GY9918@twins.programming.kicks-ass.net Cc: Adrian Hunter Cc: Arnaldo Carvalho de Melo Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-0ywfthh4lh65swe15f6w2x2q@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- kernel/events/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 2d7363adf678..4575dd6e59ea 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3627,7 +3627,7 @@ static unsigned int perf_poll(struct file *file, poll_table *wait) { struct perf_event *event = file->private_data; struct ring_buffer *rb; - unsigned int events = POLL_HUP; + unsigned int events = POLLHUP; poll_wait(file, &event->waitq, wait); /* -- GitLab From 179033b3e064d2cd3f5f9945e76b0a0f0fbf4883 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 7 Aug 2014 11:48:26 -0400 Subject: [PATCH 0612/5088] perf: Add PERF_EVENT_STATE_EXIT state for events with exited task Adding new perf event state to indicate that the monitored task has exited. In this case the event stays alive until the owner task exits or close the event fd while providing the last data through the read syscall and ring buffer. Instead it needs to propagate the error info (monitored task has died) via poll and read syscalls by returning POLLHUP and 0 respectively. Signed-off-by: Jiri Olsa Acked-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20140811120102.GY9918@twins.programming.kicks-ass.net Cc: Adrian Hunter Cc: Arnaldo Carvalho de Melo Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-t5y3w8jjx6tfo5w8y6oajsjq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/perf_event.h | 1 + kernel/events/core.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index f0a1036b1911..893a0d07986f 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -269,6 +269,7 @@ struct pmu { * enum perf_event_active_state - the states of a event */ enum perf_event_active_state { + PERF_EVENT_STATE_EXIT = -3, PERF_EVENT_STATE_ERROR = -2, PERF_EVENT_STATE_OFF = -1, PERF_EVENT_STATE_INACTIVE = 0, diff --git a/kernel/events/core.c b/kernel/events/core.c index 4575dd6e59ea..d8cb4d21a346 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3600,7 +3600,8 @@ perf_read_hw(struct perf_event *event, char __user *buf, size_t count) * error state (i.e. because it was pinned but it couldn't be * scheduled on to the CPU at some point). */ - if (event->state == PERF_EVENT_STATE_ERROR) + if ((event->state == PERF_EVENT_STATE_ERROR) || + (event->state == PERF_EVENT_STATE_EXIT)) return 0; if (count < event->read_size) @@ -3630,6 +3631,10 @@ static unsigned int perf_poll(struct file *file, poll_table *wait) unsigned int events = POLLHUP; poll_wait(file, &event->waitq, wait); + + if (event->state == PERF_EVENT_STATE_EXIT) + return events; + /* * Pin the event->rb by taking event->mmap_mutex; otherwise * perf_event_set_output() can swizzle our rb and make us miss wakeups. @@ -7588,6 +7593,9 @@ __perf_event_exit_task(struct perf_event *child_event, if (child_event->parent) { sync_child_event(child_event, child); free_event(child_event); + } else { + child_event->state = PERF_EVENT_STATE_EXIT; + perf_event_wakeup(child_event); } } -- GitLab From 3969cc094a9dbb40e624b259caa73c7a2056b249 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 15 Aug 2014 16:24:45 -0300 Subject: [PATCH 0613/5088] perf top: Use set_term_quiet() instead of open coded equivalent Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-h7n9te70flmaqfnj6l06ay6r@git.kernel.org [ Yanked this out of a patch containing this and some other change ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a77ff6ca5fbd..9848e270b92c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -433,18 +433,13 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) if (!perf_top__key_mapped(top, c)) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; - struct termios tc, save; + struct termios save; perf_top__print_mapped_keys(top); fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); fflush(stdout); - tcgetattr(0, &save); - tc = save; - tc.c_lflag &= ~(ICANON | ECHO); - tc.c_cc[VMIN] = 0; - tc.c_cc[VTIME] = 0; - tcsetattr(0, TCSANOW, &tc); + set_term_quiet_input(&save); poll(&stdin_poll, 1, -1); c = getc(stdin); -- GitLab From 2f3f9bcf000b2043a480e7cc0cae582559fb0f13 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 22 Aug 2014 15:58:38 +0200 Subject: [PATCH 0614/5088] perf tools: Add +field argument support for --field option Adding support to add field(s) to default field order via using the '+' prefix, like for report: $ perf report Samples: 10 of event 'cycles', Event count (approx.): 4463799 Overhead Command Shared Object Symbol 32.40% ls [kernel.kallsyms] [k] filemap_fault 28.19% ls [kernel.kallsyms] [k] get_page_from_freelist 23.38% ls [kernel.kallsyms] [k] enqueue_entity 15.04% ls [kernel.kallsyms] [k] mmap_region $ perf report -F +period,sample Samples: 10 of event 'cycles', Event count (approx.): 4463799 Overhead Period Samples Command Shared Object Symbol 32.40% 1446493 1 ls [kernel.kallsyms] [k] filemap_fault 28.19% 1258486 1 ls [kernel.kallsyms] [k] get_page_from_freelist 23.38% 1043754 1 ls [kernel.kallsyms] [k] enqueue_entity 15.04% 671160 1 ls [kernel.kallsyms] [k] mmap_region Works in general for commands using --field option. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jean Pihet Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1408715919-25990-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/hist.c | 4 ++-- tools/perf/util/sort.c | 24 +++++++++++++++++++----- tools/perf/util/sort.h | 1 + 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 75eb6ac821f8..2af18376b077 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -452,7 +452,7 @@ void perf_hpp__init(void) /* * If user specified field order, no need to setup default fields. */ - if (field_order) + if (is_strict_order(field_order)) return; if (symbol_conf.cumulate_callchain) { @@ -519,7 +519,7 @@ void perf_hpp__column_disable(unsigned col) void perf_hpp__cancel_cumulate(void) { - if (field_order) + if (is_strict_order(field_order)) return; perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index b4a805e5e440..1958637cf136 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1453,7 +1453,7 @@ static int __setup_sorting(void) int ret = 0; if (sort_keys == NULL) { - if (field_order) { + if (is_strict_order(field_order)) { /* * If user specified field order but no sort order, * we'll honor it and not add default sort orders. @@ -1639,23 +1639,36 @@ static void reset_dimensions(void) memory_sort_dimensions[i].taken = 0; } +bool is_strict_order(const char *order) +{ + return order && (*order != '+'); +} + static int __setup_output_field(void) { - char *tmp, *tok, *str; - int ret = 0; + char *tmp, *tok, *str, *strp; + int ret = -EINVAL; if (field_order == NULL) return 0; reset_dimensions(); - str = strdup(field_order); + strp = str = strdup(field_order); if (str == NULL) { error("Not enough memory to setup output fields"); return -ENOMEM; } - for (tok = strtok_r(str, ", ", &tmp); + if (!is_strict_order(field_order)) + strp++; + + if (!strlen(strp)) { + error("Invalid --fields key: `+'"); + goto out; + } + + for (tok = strtok_r(strp, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) { ret = output_field_add(tok); if (ret == -EINVAL) { @@ -1667,6 +1680,7 @@ static int __setup_output_field(void) } } +out: free(str); return ret; } diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 041f0c9cea2b..c03e4ff8beff 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -218,4 +218,5 @@ void perf_hpp__set_elide(int idx, bool elide); int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); +bool is_strict_order(const char *order); #endif /* __PERF_SORT_H */ -- GitLab From 39ee533fcc7feb5b7938a3973a2bf5ad79bb595b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 22 Aug 2014 09:13:21 +0900 Subject: [PATCH 0615/5088] perf hists browser: Consolidate callchain print functions in TUI Currently there're two callchain print functions in TUI - one for the hists browser and another for file dump. They do almost same job so it'd be better consolidate the codes. To do that, provide two callbacks to the generic logic - one for printing and another for checking whether it should stop. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1408666401-594-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 203 +++++++++++++-------------------- 1 file changed, 80 insertions(+), 123 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 519353d9f5fb..d4cef68176da 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -477,20 +477,37 @@ static char *callchain_list__sym_name(struct callchain_list *cl, return bf; } +struct callchain_print_arg { + /* for hists browser */ + off_t row_offset; + bool is_current_entry; + + /* for file dump */ + FILE *fp; + int printed; +}; + +typedef void (*print_callchain_entry_fn)(struct hist_browser *browser, + struct callchain_list *chain, + const char *str, int offset, + unsigned short row, + struct callchain_print_arg *arg); + static void hist_browser__show_callchain_entry(struct hist_browser *browser, struct callchain_list *chain, - unsigned short row, int offset, - char folded_sign, const char *str, - bool *is_current_entry) + const char *str, int offset, + unsigned short row, + struct callchain_print_arg *arg) { int color, width; + char folded_sign = callchain_list__folded(chain); color = HE_COLORSET_NORMAL; width = browser->b.width - (offset + 2); if (ui_browser__is_current_entry(&browser->b, row)) { browser->selection = &chain->ms; color = HE_COLORSET_SELECTED; - *is_current_entry = true; + arg->is_current_entry = true; } ui_browser__set_color(&browser->b, color); @@ -500,12 +517,41 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser, slsmg_write_nstring(str, width); } +static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused, + struct callchain_list *chain, + const char *str, int offset, + unsigned short row __maybe_unused, + struct callchain_print_arg *arg) +{ + char folded_sign = callchain_list__folded(chain); + + arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ", + folded_sign, str); +} + +typedef bool (*check_output_full_fn)(struct hist_browser *browser, + unsigned short row); + +static bool hist_browser__check_output_full(struct hist_browser *browser, + unsigned short row) +{ + return browser->b.rows == row; +} + +static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused, + unsigned short row __maybe_unused) +{ + return false; +} + #define LEVEL_OFFSET_STEP 3 static int hist_browser__show_callchain(struct hist_browser *browser, struct rb_root *root, int level, - unsigned short row, off_t *row_offset, - u64 total, bool *is_current_entry) + unsigned short row, u64 total, + print_callchain_entry_fn print, + struct callchain_print_arg *arg, + check_output_full_fn is_output_full) { struct rb_node *node; int first_row = row, offset = level * LEVEL_OFFSET_STEP; @@ -532,8 +578,8 @@ static int hist_browser__show_callchain(struct hist_browser *browser, extra_offset = LEVEL_OFFSET_STEP; folded_sign = callchain_list__folded(chain); - if (*row_offset != 0) { - --*row_offset; + if (arg->row_offset != 0) { + arg->row_offset--; goto do_next; } @@ -550,13 +596,11 @@ static int hist_browser__show_callchain(struct hist_browser *browser, str = alloc_str; } - hist_browser__show_callchain_entry(browser, chain, row, - offset + extra_offset, - folded_sign, str, - is_current_entry); + print(browser, chain, str, offset + extra_offset, row, arg); + free(alloc_str); - if (++row == browser->b.rows) + if (is_output_full(browser, ++row)) goto out; do_next: if (folded_sign == '+') @@ -572,12 +616,10 @@ static int hist_browser__show_callchain(struct hist_browser *browser, new_total = total; row += hist_browser__show_callchain(browser, &child->rb_root, - new_level, - row, row_offset, - new_total, - is_current_entry); + new_level, row, new_total, + print, arg, is_output_full); } - if (row == browser->b.rows) + if (is_output_full(browser, row)) break; node = next; } @@ -757,16 +799,20 @@ static int hist_browser__show_entry(struct hist_browser *browser, if (folded_sign == '-' && row != browser->b.rows) { u64 total = hists__total_period(entry->hists); + struct callchain_print_arg arg = { + .row_offset = row_offset, + .is_current_entry = current_entry, + }; if (symbol_conf.cumulate_callchain) total = entry->stat_acc->period; printed += hist_browser__show_callchain(browser, - &entry->sorted_chain, - 1, row, &row_offset, - total, ¤t_entry); + &entry->sorted_chain, 1, row, total, + hist_browser__show_callchain_entry, &arg, + hist_browser__check_output_full); - if (current_entry) + if (arg.is_current_entry) browser->he_selection = entry; } @@ -1022,110 +1068,21 @@ static void ui_browser__hists_seek(struct ui_browser *browser, } } -static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser, - struct callchain_node *chain_node, - u64 total, int level, - FILE *fp) -{ - struct rb_node *node; - int offset = level * LEVEL_OFFSET_STEP; - u64 new_total; - int printed = 0; - - if (callchain_param.mode == CHAIN_GRAPH_REL) - new_total = chain_node->children_hit; - else - new_total = total; - - node = rb_first(&chain_node->rb_root); - while (node) { - struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); - struct rb_node *next = rb_next(node); - u64 cumul = callchain_cumul_hits(child); - struct callchain_list *chain; - char folded_sign = ' '; - int first = true; - int extra_offset = 0; - - list_for_each_entry(chain, &child->val, list) { - char bf[1024], *alloc_str; - const char *str; - bool was_first = first; - - if (first) - first = false; - else - extra_offset = LEVEL_OFFSET_STEP; - - folded_sign = callchain_list__folded(chain); - - alloc_str = NULL; - str = callchain_list__sym_name(chain, bf, sizeof(bf), - browser->show_dso); - if (was_first) { - double percent = cumul * 100.0 / new_total; - - if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) - str = "Not enough memory!"; - else - str = alloc_str; - } - - printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str); - free(alloc_str); - if (folded_sign == '+') - break; - } - - if (folded_sign == '-') { - const int new_level = level + (extra_offset ? 2 : 1); - printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total, - new_level, fp); - } - - node = next; - } - - return printed; -} - -static int hist_browser__fprintf_callchain_node(struct hist_browser *browser, - struct callchain_node *node, - int level, FILE *fp) -{ - struct callchain_list *chain; - int offset = level * LEVEL_OFFSET_STEP; - char folded_sign = ' '; - int printed = 0; - - list_for_each_entry(chain, &node->val, list) { - char bf[1024], *s; - - folded_sign = callchain_list__folded(chain); - s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso); - printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s); - } - - if (folded_sign == '-') - printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node, - browser->hists->stats.total_period, - level + 1, fp); - return printed; -} - static int hist_browser__fprintf_callchain(struct hist_browser *browser, - struct rb_root *chain, int level, FILE *fp) + struct hist_entry *he, FILE *fp) { - struct rb_node *nd; - int printed = 0; - - for (nd = rb_first(chain); nd; nd = rb_next(nd)) { - struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); + u64 total = hists__total_period(he->hists); + struct callchain_print_arg arg = { + .fp = fp, + }; - printed += hist_browser__fprintf_callchain_node(browser, node, level, fp); - } + if (symbol_conf.cumulate_callchain) + total = he->stat_acc->period; - return printed; + hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total, + hist_browser__fprintf_callchain_entry, &arg, + hist_browser__check_dump_full); + return arg.printed; } static int hist_browser__fprintf_entry(struct hist_browser *browser, @@ -1164,7 +1121,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, printed += fprintf(fp, "%s\n", rtrim(s)); if (folded_sign == '-') - printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp); + printed += hist_browser__fprintf_callchain(browser, he, fp); return printed; } -- GitLab From 57f2d8b797c4c8d9e65e3b9fae98246be5a93df3 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 25 Aug 2014 19:04:52 +0530 Subject: [PATCH 0616/5088] ALSA: ctxfi: ctpcm.c: printk replacement replaced printk with corresponding pr_err Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctpcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index e8a4feb1ed86..6826c2c02c44 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -217,7 +217,7 @@ static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream) err = atc->pcm_playback_prepare(atc, apcm); if (err < 0) { - printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n"); + pr_err("ctxfi: Preparing pcm playback failed!!!\n"); return err; } @@ -324,7 +324,7 @@ static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream) err = atc->pcm_capture_prepare(atc, apcm); if (err < 0) { - printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n"); + pr_err("ctxfi: Preparing pcm capture failed!!!\n"); return err; } @@ -435,7 +435,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc, err = snd_pcm_new(atc->card, "ctxfi", device, playback_count, capture_count, &pcm); if (err < 0) { - printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err); + pr_err("ctxfi: snd_pcm_new failed!! Err=%d\n", err); return err; } -- GitLab From 251f8c0364f99fc21fcc7b07e4ec6b4f3250d841 Mon Sep 17 00:00:00 2001 From: Dongsheng Yang Date: Mon, 25 Aug 2014 19:27:52 +0800 Subject: [PATCH 0617/5088] cgroup: fix a typo in comment. There is no function named cgroup_enable_task_cg_links(). Instead, the correct function name in this comment should be cgroup_enabled_task_cg_lists(). Signed-off-by: Dongsheng Yang Signed-off-by: Tejun Heo --- kernel/cgroup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 7dc8788cfd52..64bbb56496c2 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -5161,7 +5161,7 @@ void cgroup_post_fork(struct task_struct *child) int i; /* - * This may race against cgroup_enable_task_cg_links(). As that + * This may race against cgroup_enable_task_cg_lists(). As that * function sets use_task_css_set_links before grabbing * tasklist_lock and we just went through tasklist_lock to add * @child, it's guaranteed that either we see the set @@ -5176,7 +5176,7 @@ void cgroup_post_fork(struct task_struct *child) * when implementing operations which need to migrate all tasks of * a cgroup to another. * - * Note that if we lose to cgroup_enable_task_cg_links(), @child + * Note that if we lose to cgroup_enable_task_cg_lists(), @child * will remain in init_css_set. This is safe because all tasks are * in the init_css_set before cg_links is enabled and there's no * operation which transfers all tasks out of init_css_set. -- GitLab From d83d2c26461d661384676a4eed935d925b0fcc34 Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Tue, 19 Aug 2014 14:26:32 +0200 Subject: [PATCH 0618/5088] Smack: Fix setting label on successful file open While opening with CAP_MAC_OVERRIDE file label is not set. Other calls may access it after CAP_MAC_OVERRIDE is dropped from process. Signed-off-by: Marcin Niesluchowski --- security/smack/smack_lsm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 16ae8534b14c..7091b46adab2 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1477,8 +1477,10 @@ static int smack_file_open(struct file *file, const struct cred *cred) struct smk_audit_info ad; int rc; - if (smack_privileged(CAP_MAC_OVERRIDE)) + if (smack_privileged(CAP_MAC_OVERRIDE)) { + file->f_security = isp->smk_inode; return 0; + } smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); -- GitLab From 90114d65feea716eeae0ab51e92c95b140b2e6fc Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 25 Aug 2014 13:02:52 +0200 Subject: [PATCH 0619/5088] s390: Implement dma_{alloc,free}_attrs() The S390 architecture advertises support for HAVE_DMA_ATTRS when PCI is enabled. Patches to unify some of the DMA API would like to rely on the dma_alloc_attrs() and dma_free_attrs() functions to be provided when an architecture supports DMA attributes. Rename dma_alloc_coherent() and dma_free_coherent() to dma_alloc_attrs() and dma_free_attrs() since they are functionally equivalent and alias the former to the latter for compatibility. For consistency with other architectures, also reuse the existing symbol HAVE_DMA_ATTRS defined in arch/Kconfig instead of providing a duplicate. Select it when PCI is enabled. While at it, drop a redundant 'default n' from the PCI Kconfig symbol. Signed-off-by: Thierry Reding Acked-By: Sebastian Ott Signed-off-by: Marek Szyprowski --- arch/s390/Kconfig | 5 +---- arch/s390/include/asm/dma-mapping.h | 31 +++++++++++++++++++---------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index ab39ceb89ecf..fafeae01725a 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -498,8 +498,8 @@ config QDIO menuconfig PCI bool "PCI support" - default n depends on 64BIT + select HAVE_DMA_ATTRS select PCI_MSI help Enable PCI support. @@ -546,9 +546,6 @@ config HAS_DMA config NEED_SG_DMA_LENGTH def_bool PCI -config HAVE_DMA_ATTRS - def_bool PCI - config NEED_DMA_MAP_STATE def_bool PCI diff --git a/arch/s390/include/asm/dma-mapping.h b/arch/s390/include/asm/dma-mapping.h index 3fbc67d9e197..709955ddaa4d 100644 --- a/arch/s390/include/asm/dma-mapping.h +++ b/arch/s390/include/asm/dma-mapping.h @@ -56,24 +56,35 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) return dma_addr == DMA_ERROR_CODE; } -static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) +#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 *ret; + void *cpu_addr; + + BUG_ON(!ops); - ret = ops->alloc(dev, size, dma_handle, flag, NULL); - debug_dma_alloc_coherent(dev, size, *dma_handle, ret); - return ret; + cpu_addr = ops->alloc(dev, size, dma_handle, flags, attrs); + debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); + + return cpu_addr; } -static inline void dma_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) +#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); + struct dma_map_ops *ops = get_dma_ops(dev); + + BUG_ON(!ops); debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); - dma_ops->free(dev, size, cpu_addr, dma_handle, NULL); + ops->free(dev, size, cpu_addr, dma_handle, attrs); } #endif /* _ASM_S390_DMA_MAPPING_H */ -- GitLab From b4bbb107d73bbc0d92c9ae7fd8e69580aa9381e7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 27 Jun 2014 11:56:58 +0200 Subject: [PATCH 0620/5088] dma-mapping: Provide write-combine allocations Provide an implementation for dma_{alloc,free,mmap}_writecombine() when the architecture supports DMA attributes. Signed-off-by: Thierry Reding Acked-by: Arnd Bergmann Signed-off-by: Marek Szyprowski --- arch/arm/include/asm/dma-mapping.h | 16 --------------- include/asm-generic/dma-mapping-common.h | 8 -------- include/linux/dma-mapping.h | 26 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index c45b61a4b4a5..85738b200023 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -265,22 +265,6 @@ extern int arm_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); -static inline void *dma_alloc_writecombine(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ - DEFINE_DMA_ATTRS(attrs); - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); - return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs); -} - -static inline void dma_free_writecombine(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) -{ - DEFINE_DMA_ATTRS(attrs); - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); - return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs); -} - /* * This can be called during early boot to increase the size of the atomic * coherent DMA pool above the default value of 256KiB. It must be called diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h index de8bf89940f8..d137431bf26f 100644 --- a/include/asm-generic/dma-mapping-common.h +++ b/include/asm-generic/dma-mapping-common.h @@ -205,14 +205,6 @@ dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, #define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL) -static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size) -{ - DEFINE_DMA_ATTRS(attrs); - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); - return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs); -} - int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, void *cpu_addr, dma_addr_t dma_addr, size_t size); diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 931b70986272..d5d388160f42 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -263,6 +263,32 @@ struct dma_attrs; #define dma_unmap_sg_attrs(dev, sgl, nents, dir, attrs) \ dma_unmap_sg(dev, sgl, nents, dir) +#else +static inline void *dma_alloc_writecombine(struct device *dev, size_t size, + dma_addr_t *dma_addr, gfp_t gfp) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + return dma_alloc_attrs(dev, size, dma_addr, gfp, &attrs); +} + +static inline void dma_free_writecombine(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_addr) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + return dma_free_attrs(dev, size, cpu_addr, dma_addr, &attrs); +} + +static inline int dma_mmap_writecombine(struct device *dev, + struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, + size_t size) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs); +} #endif /* CONFIG_HAVE_DMA_ATTRS */ #ifdef CONFIG_NEED_DMA_MAP_STATE -- GitLab From 5819c2fa55d4a6eaf7fe025a393dce98fc4b2116 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 24 Aug 2014 15:36:55 +0200 Subject: [PATCH 0621/5088] ASoC: Restore idle_bias_off initialization This was accidentally lost in commit f1d45cc3ae96 ("ASoC: Consolidate platform and CODEC probe/remove"). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c36983a133fa..419682693886 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4010,6 +4010,7 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, dapm->dev = dev; dapm->component = component; dapm->bias_level = SND_SOC_BIAS_OFF; + dapm->idle_bias_off = true; if (driver->seq_notifier) dapm->seq_notifier = snd_soc_component_seq_notifier; if (driver->stream_event) @@ -4399,6 +4400,7 @@ int snd_soc_register_codec(struct device *dev, codec->component.read = snd_soc_codec_drv_read; codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; codec->dapm.codec = codec; + codec->dapm.idle_bias_off = codec_drv->idle_bias_off; if (codec_drv->seq_notifier) codec->dapm.seq_notifier = codec_drv->seq_notifier; if (codec_drv->set_bias_level) -- GitLab From 50917e265ebd2ea33bc34b22b3981f1e88415eae Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 5 Aug 2014 16:38:38 +0200 Subject: [PATCH 0622/5088] iommu/amd: Move struct iommu_dev_data to amd_iommu.c The struct is only used there, so it doesn't need to be in the header file. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 21 +++++++++++++++++++++ drivers/iommu/amd_iommu_types.h | 21 --------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index ecb0109a5360..fe6d7cc715f7 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -87,6 +87,27 @@ int amd_iommu_max_glx_val = -1; static struct dma_map_ops amd_iommu_dma_ops; +/* + * This struct contains device specific data for the IOMMU + */ +struct iommu_dev_data { + struct list_head list; /* For domain->dev_list */ + struct list_head dev_data_list; /* For global dev_data_list */ + struct iommu_dev_data *alias_data;/* The alias dev_data */ + struct protection_domain *domain; /* Domain the device is bound to */ + atomic_t bind; /* Domain attach reference count */ + u16 devid; /* PCI Device ID */ + bool iommu_v2; /* Device can make use of IOMMUv2 */ + bool passthrough; /* Default for device is pt_domain */ + struct { + bool enabled; + int qdep; + } ats; /* ATS state */ + bool pri_tlp; /* PASID TLB required for + PPR completions */ + u32 errata; /* Bitmap for errata to apply */ +}; + /* * general struct to manage commands send to an IOMMU */ diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 8e43b7cba133..cec51a8ba844 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -417,27 +417,6 @@ struct protection_domain { }; -/* - * This struct contains device specific data for the IOMMU - */ -struct iommu_dev_data { - struct list_head list; /* For domain->dev_list */ - struct list_head dev_data_list; /* For global dev_data_list */ - struct iommu_dev_data *alias_data;/* The alias dev_data */ - struct protection_domain *domain; /* Domain the device is bound to */ - atomic_t bind; /* Domain attach reference count */ - u16 devid; /* PCI Device ID */ - bool iommu_v2; /* Device can make use of IOMMUv2 */ - bool passthrough; /* Default for device is pt_domain */ - struct { - bool enabled; - int qdep; - } ats; /* ATS state */ - bool pri_tlp; /* PASID TLB required for - PPR completions */ - u32 errata; /* Bitmap for errata to apply */ -}; - /* * For dynamic growth the aperture size is split into ranges of 128MB of * DMA address space each. This struct represents one such range. -- GitLab From f251e187f2949c690fc13a91df7b873a6b5be671 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 5 Aug 2014 16:48:10 +0200 Subject: [PATCH 0623/5088] iommu/amd: Keep a list of devices in an alias group Some broken devices might use any request-id from the alias group, so we need to set a DTE entry for every device in there. This patch adds creation of those lists. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index fe6d7cc715f7..8a152564a098 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -93,6 +93,7 @@ static struct dma_map_ops amd_iommu_dma_ops; struct iommu_dev_data { struct list_head list; /* For domain->dev_list */ struct list_head dev_data_list; /* For global dev_data_list */ + struct list_head alias_list; /* Link alias-groups together */ struct iommu_dev_data *alias_data;/* The alias dev_data */ struct protection_domain *domain; /* Domain the device is bound to */ atomic_t bind; /* Domain attach reference count */ @@ -135,6 +136,8 @@ static struct iommu_dev_data *alloc_dev_data(u16 devid) if (!dev_data) return NULL; + INIT_LIST_HEAD(&dev_data->alias_list); + dev_data->devid = devid; atomic_set(&dev_data->bind, 0); @@ -383,6 +386,9 @@ static int iommu_init_device(struct device *dev) return -ENOTSUPP; } dev_data->alias_data = alias_data; + + /* Add device to the alias_list */ + list_add(&dev_data->alias_list, &alias_data->alias_list); } ret = init_iommu_group(dev); -- GitLab From 397111abaaac259afcc48cd2fbfb78f63f27e797 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 5 Aug 2014 17:31:51 +0200 Subject: [PATCH 0624/5088] iommu/amd: Attach and detach complete alias group Change tha device attach and detach semantic to apply to all devices in an alias group. This means all devices in an alias group are now attached and detached at the same time. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 46 +++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 8a152564a098..a5e6b0a2de16 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2149,35 +2149,29 @@ static void do_detach(struct iommu_dev_data *dev_data) static int __attach_device(struct iommu_dev_data *dev_data, struct protection_domain *domain) { + struct iommu_dev_data *head, *entry; int ret; /* lock domain */ spin_lock(&domain->lock); - if (dev_data->alias_data != NULL) { - struct iommu_dev_data *alias_data = dev_data->alias_data; - - /* Some sanity checks */ - ret = -EBUSY; - if (alias_data->domain != NULL && - alias_data->domain != domain) - goto out_unlock; + head = dev_data; - if (dev_data->domain != NULL && - dev_data->domain != domain) - goto out_unlock; + if (head->alias_data != NULL) + head = head->alias_data; - /* Do real assignment */ - if (alias_data->domain == NULL) - do_attach(alias_data, domain); + /* Now we have the root of the alias group, if any */ - atomic_inc(&alias_data->bind); - } + ret = -EBUSY; + if (head->domain != NULL) + goto out_unlock; - if (dev_data->domain == NULL) - do_attach(dev_data, domain); + /* Attach alias group root */ + do_attach(head, domain); - atomic_inc(&dev_data->bind); + /* Attach other devices in the alias group */ + list_for_each_entry(entry, &head->alias_list, alias_list) + do_attach(entry, domain); ret = 0; @@ -2325,6 +2319,7 @@ static int attach_device(struct device *dev, */ static void __detach_device(struct iommu_dev_data *dev_data) { + struct iommu_dev_data *head, *entry; struct protection_domain *domain; unsigned long flags; @@ -2334,15 +2329,14 @@ static void __detach_device(struct iommu_dev_data *dev_data) spin_lock_irqsave(&domain->lock, flags); - if (dev_data->alias_data != NULL) { - struct iommu_dev_data *alias_data = dev_data->alias_data; + head = dev_data; + if (head->alias_data != NULL) + head = head->alias_data; - if (atomic_dec_and_test(&alias_data->bind)) - do_detach(alias_data); - } + list_for_each_entry(entry, &head->alias_list, alias_list) + do_detach(entry); - if (atomic_dec_and_test(&dev_data->bind)) - do_detach(dev_data); + do_detach(head); spin_unlock_irqrestore(&domain->lock, flags); -- GitLab From cafd2545cfd36ef6fee14f9c36870b81d3c98de5 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 5 Aug 2014 17:34:25 +0200 Subject: [PATCH 0625/5088] iommu/amd: Remove device binding reference count This reference count is not used anymore, as all devices in an alias group are now attached and detached together. Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index a5e6b0a2de16..989c1ae03979 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -96,7 +96,6 @@ struct iommu_dev_data { struct list_head alias_list; /* Link alias-groups together */ struct iommu_dev_data *alias_data;/* The alias dev_data */ struct protection_domain *domain; /* Domain the device is bound to */ - atomic_t bind; /* Domain attach reference count */ u16 devid; /* PCI Device ID */ bool iommu_v2; /* Device can make use of IOMMUv2 */ bool passthrough; /* Default for device is pt_domain */ @@ -139,7 +138,6 @@ static struct iommu_dev_data *alloc_dev_data(u16 devid) INIT_LIST_HEAD(&dev_data->alias_list); dev_data->devid = devid; - atomic_set(&dev_data->bind, 0); spin_lock_irqsave(&dev_data_list_lock, flags); list_add_tail(&dev_data->dev_data_list, &dev_data_list); @@ -3179,7 +3177,6 @@ static void cleanup_domain(struct protection_domain *domain) entry = list_first_entry(&domain->dev_list, struct iommu_dev_data, list); __detach_device(entry); - atomic_set(&entry->bind, 0); } write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); -- GitLab From 604effb782a8a4d9a20c8af16bcbf86d742db119 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 26 Aug 2014 13:26:56 +0300 Subject: [PATCH 0626/5088] drm/i915: fix suspend/resume for GENs w/o runtime PM support Before sharing common parts between the system and runtime s/r handlers we WARNed if the runtime s/r handlers were called on GENs that didn't support RPM. But this WARN is not correct if the same handler is called from the system s/r path, since that can happen on any platform. This also broke system s/r on old platforms. The issue was introduced in commit 016970beb05da6285c2f3ed2bee1c676cb75972e Author: Sagar Kamble Date: Wed Aug 13 23:07:06 2014 +0530 v2: - remove the WARN and depend on the HAS_RUNTIME_PM check in rutime_suspend/resume instead (Daniel) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=82751 Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 117f5c16df74..0f7a522682a5 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1373,7 +1373,9 @@ static int intel_runtime_suspend(struct device *device) if (WARN_ON_ONCE(!(dev_priv->rps.enabled && intel_enable_rc6(dev)))) return -ENODEV; - WARN_ON(!HAS_RUNTIME_PM(dev)); + if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev))) + return -ENODEV; + assert_force_wake_inactive(dev_priv); DRM_DEBUG_KMS("Suspending device\n"); @@ -1441,7 +1443,8 @@ static int intel_runtime_resume(struct device *device) struct drm_i915_private *dev_priv = dev->dev_private; int ret; - WARN_ON(!HAS_RUNTIME_PM(dev)); + if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev))) + return -ENODEV; DRM_DEBUG_KMS("Resuming device\n"); @@ -1476,16 +1479,12 @@ static int intel_suspend_complete(struct drm_i915_private *dev_priv) struct drm_device *dev = dev_priv->dev; int ret; - if (IS_GEN6(dev)) { - ret = 0; - } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) ret = hsw_suspend_complete(dev_priv); - } else if (IS_VALLEYVIEW(dev)) { + else if (IS_VALLEYVIEW(dev)) ret = vlv_suspend_complete(dev_priv); - } else { - ret = -ENODEV; - WARN_ON(1); - } + else + ret = 0; return ret; } @@ -1501,16 +1500,14 @@ static int intel_resume_prepare(struct drm_i915_private *dev_priv, struct drm_device *dev = dev_priv->dev; int ret; - if (IS_GEN6(dev)) { + if (IS_GEN6(dev)) ret = snb_resume_prepare(dev_priv, rpm_resume); - } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) ret = hsw_resume_prepare(dev_priv, rpm_resume); - } else if (IS_VALLEYVIEW(dev)) { + else if (IS_VALLEYVIEW(dev)) ret = vlv_resume_prepare(dev_priv, rpm_resume); - } else { - WARN_ON(1); - ret = -ENODEV; - } + else + ret = 0; return ret; } -- GitLab From 68ecfe2fe2e6c636bb7e2cf616e658e342e05362 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 8 Aug 2014 12:07:55 +0200 Subject: [PATCH 0627/5088] video: of: display_timing: delete unneeded test before of_node_put MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Of_node_put supports NULL as its argument, so the initial test is not necessary. Furthermore, native_mode cannot be NULL at this point. Suggested by Uwe Kleine-König. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression e; @@ -if (e) of_node_put(e); // Signed-off-by: Julia Lawall Signed-off-by: Tomi Valkeinen --- drivers/video/of_display_timing.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c index 987edf110038..339f831c8412 100644 --- a/drivers/video/of_display_timing.c +++ b/drivers/video/of_display_timing.c @@ -233,8 +233,7 @@ struct display_timings *of_get_display_timings(struct device_node *np) return disp; timingfail: - if (native_mode) - of_node_put(native_mode); + of_node_put(native_mode); display_timings_release(disp); entryfail: kfree(disp); -- GitLab From 1287c5bf214b906d64a71c481545010dbe1b5b66 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 23 Aug 2014 13:20:24 +0200 Subject: [PATCH 0628/5088] video: fbdev: matrox: use c99 initializers in structures Use c99 initializers for structures. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @decl@ identifier i1,fld; type T; field list[n] fs; @@ struct i1 { fs T fld; ...}; @bad@ identifier decl.i1,i2; expression e; initializer list[decl.n] is; @@ struct i1 i2 = { is, + .fld = e - e ,...}; // Signed-off-by: Julia Lawall Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/matrox/matroxfb_base.c | 52 ++++++++++++++++++--- drivers/video/fbdev/matrox/matroxfb_maven.c | 20 ++++---- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c index 7116c5309c7d..62539ca1cfa9 100644 --- a/drivers/video/fbdev/matrox/matroxfb_base.c +++ b/drivers/video/fbdev/matrox/matroxfb_base.c @@ -1341,19 +1341,57 @@ struct video_board { struct matrox_switch* lowlevel; }; #ifdef CONFIG_FB_MATROX_MILLENIUM -static struct video_board vbMillennium = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millennium}; -static struct video_board vbMillennium2 = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W, &matrox_millennium}; -static struct video_board vbMillennium2A = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millennium}; +static struct video_board vbMillennium = { + .maxvram = 0x0800000, + .maxdisplayable = 0x0800000, + .accelID = FB_ACCEL_MATROX_MGA2064W, + .lowlevel = &matrox_millennium +}; + +static struct video_board vbMillennium2 = { + .maxvram = 0x1000000, + .maxdisplayable = 0x0800000, + .accelID = FB_ACCEL_MATROX_MGA2164W, + .lowlevel = &matrox_millennium +}; + +static struct video_board vbMillennium2A = { + .maxvram = 0x1000000, + .maxdisplayable = 0x0800000, + .accelID = FB_ACCEL_MATROX_MGA2164W_AGP, + .lowlevel = &matrox_millennium +}; #endif /* CONFIG_FB_MATROX_MILLENIUM */ #ifdef CONFIG_FB_MATROX_MYSTIQUE -static struct video_board vbMystique = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique}; +static struct video_board vbMystique = { + .maxvram = 0x0800000, + .maxdisplayable = 0x0800000, + .accelID = FB_ACCEL_MATROX_MGA1064SG, + .lowlevel = &matrox_mystique +}; #endif /* CONFIG_FB_MATROX_MYSTIQUE */ #ifdef CONFIG_FB_MATROX_G -static struct video_board vbG100 = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100}; -static struct video_board vbG200 = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100}; +static struct video_board vbG100 = { + .maxvram = 0x0800000, + .maxdisplayable = 0x0800000, + .accelID = FB_ACCEL_MATROX_MGAG100, + .lowlevel = &matrox_G100 +}; + +static struct video_board vbG200 = { + .maxvram = 0x1000000, + .maxdisplayable = 0x1000000, + .accelID = FB_ACCEL_MATROX_MGAG200, + .lowlevel = &matrox_G100 +}; /* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for whole 32MB */ -static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100}; +static struct video_board vbG400 = { + .maxvram = 0x2000000, + .maxdisplayable = 0x1000000, + .accelID = FB_ACCEL_MATROX_MGAG400, + .lowlevel = &matrox_G100 +}; #endif #define DEVF_VIDEO64BIT 0x0001 diff --git a/drivers/video/fbdev/matrox/matroxfb_maven.c b/drivers/video/fbdev/matrox/matroxfb_maven.c index ee41a0f276b2..bf5ce04f9aea 100644 --- a/drivers/video/fbdev/matrox/matroxfb_maven.c +++ b/drivers/video/fbdev/matrox/matroxfb_maven.c @@ -201,21 +201,23 @@ struct matrox_pll_ctl { }; static const struct matrox_pll_features2 maven1000_pll = { - 50000000, - 300000000, - 5, 128, - 3, 32, - 3 + .vco_freq_min = 50000000, + .vco_freq_max = 300000000, + .feed_div_min = 5, + .feed_div_max = 128, + .in_div_min = 3, + .in_div_max = 32, + .post_shift_max = 3 }; static const struct matrox_pll_ctl maven_PAL = { - 540000, - 50 + .ref_freq = 540000, + .den = 50 }; static const struct matrox_pll_ctl maven_NTSC = { - 450450, /* 27027000/60 == 27000000/59.94005994 */ - 60 + .ref_freq = 450450, /* 27027000/60 == 27000000/59.94005994 */ + .den = 60 }; static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, -- GitLab From 39917f08721b2f04d06407777ce7ae5913533674 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 23 Aug 2014 13:20:29 +0200 Subject: [PATCH 0629/5088] OMAPDSS: DSI: use c99 initializers in structures Use c99 initializers for structures. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @decl@ identifier i1,fld; type T; field list[n] fs; @@ struct i1 { fs T fld; ...}; @bad@ identifier decl.i1,i2; expression e; initializer list[decl.n] is; @@ struct i1 i2 = { is, + .fld = e - e ,...}; // Signed-off-by: Julia Lawall Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/omap2/dss/dsi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c index 56b92444c54f..b6f6ae1d4664 100644 --- a/drivers/video/fbdev/omap2/dss/dsi.c +++ b/drivers/video/fbdev/omap2/dss/dsi.c @@ -2571,7 +2571,10 @@ static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DECLARE_COMPLETION_ONSTACK(completion); - struct dsi_packet_sent_handler_data vp_data = { dsidev, &completion }; + struct dsi_packet_sent_handler_data vp_data = { + .dsidev = dsidev, + .completion = &completion + }; int r = 0; u8 bit; @@ -2617,7 +2620,10 @@ static void dsi_packet_sent_handler_l4(void *data, u32 mask) static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel) { DECLARE_COMPLETION_ONSTACK(completion); - struct dsi_packet_sent_handler_data l4_data = { dsidev, &completion }; + struct dsi_packet_sent_handler_data l4_data = { + .dsidev = dsidev, + .completion = &completion + }; int r = 0; r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4, -- GitLab From 084244646217ec83970facaf7baf200c02a8183e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 23 Aug 2014 17:50:28 +0200 Subject: [PATCH 0630/5088] video: fbdev: aty: use c99 initializers in structures Use c99 initializers for structures. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @decl@ identifier i1,fld; type T; field list[n] fs; @@ struct i1 { fs T fld; ...}; @bad@ identifier decl.i1,i2; expression e; initializer list[decl.n] is; @@ struct i1 i2 = { is, + .fld = e - e ,...}; // Signed-off-by: Julia Lawall Reviewed-by: Josh Triplett Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/aty/aty128fb.c | 63 ++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index ff6070170d01..aedf2fbf9bf6 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -324,14 +324,61 @@ struct aty128_meminfo { }; /* various memory configurations */ -static const struct aty128_meminfo sdr_128 = - { 4, 4, 3, 3, 1, 3, 1, 16, 30, 16, "128-bit SDR SGRAM (1:1)" }; -static const struct aty128_meminfo sdr_64 = - { 4, 8, 3, 3, 1, 3, 1, 17, 46, 17, "64-bit SDR SGRAM (1:1)" }; -static const struct aty128_meminfo sdr_sgram = - { 4, 4, 1, 2, 1, 2, 1, 16, 24, 16, "64-bit SDR SGRAM (2:1)" }; -static const struct aty128_meminfo ddr_sgram = - { 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" }; +static const struct aty128_meminfo sdr_128 = { + .ML = 4, + .MB = 4, + .Trcd = 3, + .Trp = 3, + .Twr = 1, + .CL = 3, + .Tr2w = 1, + .LoopLatency = 16, + .DspOn = 30, + .Rloop = 16, + .name = "128-bit SDR SGRAM (1:1)", +}; + +static const struct aty128_meminfo sdr_64 = { + .ML = 4, + .MB = 8, + .Trcd = 3, + .Trp = 3, + .Twr = 1, + .CL = 3, + .Tr2w = 1, + .LoopLatency = 17, + .DspOn = 46, + .Rloop = 17, + .name = "64-bit SDR SGRAM (1:1)", +}; + +static const struct aty128_meminfo sdr_sgram = { + .ML = 4, + .MB = 4, + .Trcd = 1, + .Trp = 2, + .Twr = 1, + .CL = 2, + .Tr2w = 1, + .LoopLatency = 16, + .DspOn = 24, + .Rloop = 16, + .name = "64-bit SDR SGRAM (2:1)", +}; + +static const struct aty128_meminfo ddr_sgram = { + .ML = 4, + .MB = 4, + .Trcd = 3, + .Trp = 3, + .Twr = 2, + .CL = 3, + .Tr2w = 1, + .LoopLatency = 16, + .DspOn = 31, + .Rloop = 16, + .name = "64-bit DDR SGRAM", +}; static struct fb_fix_screeninfo aty128fb_fix = { .id = "ATY Rage128", -- GitLab From c76031f3ece10939d87cc96857b9e045133064e6 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 8 Jul 2014 18:27:18 +0200 Subject: [PATCH 0631/5088] video: vermilion: remove unnecessary break after goto Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: Jingoo Han Cc: linux-fbdev@vger.kernel.org Signed-off-by: Fabian Frederick Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/vermilion/vermilion.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/video/fbdev/vermilion/vermilion.c b/drivers/video/fbdev/vermilion/vermilion.c index 048a66640b03..5f930aeccf1f 100644 --- a/drivers/video/fbdev/vermilion/vermilion.c +++ b/drivers/video/fbdev/vermilion/vermilion.c @@ -481,7 +481,6 @@ static int vml_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) default: err = -ENODEV; goto out_err_1; - break; } info = &vinfo->info; -- GitLab From 87306c1d09c8dd7ed291a6b5d6c31323cd81f2ae Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 11 Jul 2014 18:13:27 +0200 Subject: [PATCH 0632/5088] video: mx3fb: Update comment for dmaengine_prep_slave_sg() API Commit 16052827d98fbc13c31ebad560af4bd53e2b4dd5 ("dmaengine/dma_slave: introduce inline wrappers") changed the code to use the new API, but forgot to update a comment. Signed-off-by: Geert Uytterhoeven Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: Jiri Kosina Cc: linux-fbdev@vger.kernel.org -- v2: - New Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/mx3fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c index c645a0a0c341..5e97baf92721 100644 --- a/drivers/video/fbdev/mx3fb.c +++ b/drivers/video/fbdev/mx3fb.c @@ -1179,7 +1179,7 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var, /* * We enable the End of Frame interrupt, which will free a tx-descriptor, - * which we will need for the next device_prep_slave_sg(). The + * which we will need for the next dmaengine_prep_slave_sg(). The * IRQ-handler will disable the IRQ again. */ init_completion(&mx3_fbi->flip_cmpl); -- GitLab From 0c46575f7c7dea4068924f2c0d938232f68a5cda Mon Sep 17 00:00:00 2001 From: Pramod Gurav Date: Tue, 26 Aug 2014 17:40:37 +0530 Subject: [PATCH 0633/5088] msm: msm_fb: Add remove function for platform driver for clean unloading This adds a remove function to platform driver structure so that resources are released when driver is unloaded. Signed-off-by: Pramod Gurav CC: Jean-Christophe Plagniol-Villard CC: Tomi Valkeinen CC: Stephen Boyd CC: Jingoo Han CC: Rob Clark Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/msm/msm_fb.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/video/fbdev/msm/msm_fb.c b/drivers/video/fbdev/msm/msm_fb.c index 1374803fbcd9..4640188ffd6e 100644 --- a/drivers/video/fbdev/msm/msm_fb.c +++ b/drivers/video/fbdev/msm/msm_fb.c @@ -589,6 +589,8 @@ static int msmfb_probe(struct platform_device *pdev) msmfb->sleeping = WAKING; + platform_set_drvdata(pdev, msmfb); + return 0; error_register_framebuffer: @@ -598,9 +600,23 @@ static int msmfb_probe(struct platform_device *pdev) return ret; } +static int msmfb_remove(struct platform_device *pdev) +{ + struct msmfb_info *msmfb; + + msmfb = platform_get_drvdata(pdev); + + unregister_framebuffer(msmfb->fb); + iounmap(msmfb->fb->screen_base); + framebuffer_release(msmfb->fb); + + return 0; +} + static struct platform_driver msm_panel_driver = { /* need to write remove */ .probe = msmfb_probe, + .remove = msmfb_remove, .driver = {.name = "msm_panel"}, }; -- GitLab From fbaa19df03f87c2aa6a3a0a14dd7d4c098d45643 Mon Sep 17 00:00:00 2001 From: Pramod Gurav Date: Tue, 26 Aug 2014 18:22:58 +0530 Subject: [PATCH 0634/5088] msm: msm_fb: Move to using managed resources of kzalloc Move to managed verion of kzalloc. Also checks return for failure case which was missing. Signed-off-by: Pramod Gurav CC: Jean-Christophe Plagniol-Villard CC: Tomi Valkeinen CC: Stephen Boyd CC: Jingoo Han CC: Rob Clark Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/msm/msm_fb.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/msm/msm_fb.c b/drivers/video/fbdev/msm/msm_fb.c index 4640188ffd6e..2979d7e72126 100644 --- a/drivers/video/fbdev/msm/msm_fb.c +++ b/drivers/video/fbdev/msm/msm_fb.c @@ -569,8 +569,13 @@ static int msmfb_probe(struct platform_device *pdev) mutex_init(&msmfb->panel_init_lock); init_waitqueue_head(&msmfb->frame_wq); INIT_WORK(&msmfb->resume_work, power_on_panel); - msmfb->black = kzalloc(msmfb->fb->var.bits_per_pixel*msmfb->xres, - GFP_KERNEL); + msmfb->black = devm_kzalloc(&pdev->dev, + msmfb->fb->var.bits_per_pixel*msmfb->xres, + GFP_KERNEL); + if (!msmfb->black) { + ret = -ENOMEM; + goto error_register_framebuffer; + } printk(KERN_INFO "msmfb_probe() installing %d x %d panel\n", msmfb->xres, msmfb->yres); -- GitLab From f57eda296dc327fc3f5d21099cf232bcd004237f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 23 Aug 2014 20:33:22 +0200 Subject: [PATCH 0635/5088] video: fbdev: riva: delete double assignment Delete successive assignments to the same location. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression i; @@ *i = ...; i = ...; // Signed-off-by: Julia Lawall Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/riva/riva_hw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/video/fbdev/riva/riva_hw.c b/drivers/video/fbdev/riva/riva_hw.c index 78fdbf5178d7..8bdf37f3013b 100644 --- a/drivers/video/fbdev/riva/riva_hw.c +++ b/drivers/video/fbdev/riva/riva_hw.c @@ -430,7 +430,6 @@ static char nv3_arb(nv3_fifo_info * res_info, nv3_sim_state * state, nv3_arb_in int mmisses, gmisses, vmisses, eburst_size, mburst_size; int refresh_cycle; - refresh_cycle = 0; refresh_cycle = 2*(state->mclk_khz/state->pclk_khz) + 5; mmisses = 2; if (state->mem_aligned) gmisses = 2; -- GitLab From 2079a513b0f03c8872322070944720d2c174b005 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 23 Aug 2014 20:33:23 +0200 Subject: [PATCH 0636/5088] video: fbdev: intelfb: delete double assignment Delete successive assignments to the same location. In the second case, = is converted to |=, which looks appropriate based on the values involved. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression i; @@ *i = ...; i = ...; // Signed-off-by: Julia Lawall Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/intelfb/intelfbhw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/video/fbdev/intelfb/intelfbhw.c b/drivers/video/fbdev/intelfb/intelfbhw.c index fbad61da359f..d31ed4e2c46f 100644 --- a/drivers/video/fbdev/intelfb/intelfbhw.c +++ b/drivers/video/fbdev/intelfb/intelfbhw.c @@ -1191,7 +1191,6 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, vsync_end = vsync_start + var->vsync_len; vtotal = vsync_end + var->upper_margin; vblank_start = vactive; - vblank_end = vtotal; vblank_end = vsync_end + 1; DBG_MSG("V: act %d, ss %d, se %d, tot %d bs %d, be %d\n", @@ -1859,7 +1858,7 @@ void intelfbhw_cursor_init(struct intelfb_info *dinfo) tmp = INREG(CURSOR_CONTROL); tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE | CURSOR_ENABLE | CURSOR_STRIDE_MASK); - tmp = CURSOR_FORMAT_3C; + tmp |= CURSOR_FORMAT_3C; OUTREG(CURSOR_CONTROL, tmp); OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.offset << 12); tmp = (64 << CURSOR_SIZE_H_SHIFT) | -- GitLab From a9a3cac6908a86ada51ab12f7eb39d0313814d23 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 23 Aug 2014 20:33:27 +0200 Subject: [PATCH 0637/5088] video: fbdev: sis: delete double assignment Delete successive assignments to the same location. The second assignment is changed to update a different field, as done in other nearby code. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression i; @@ *i = ...; i = ...; // Signed-off-by: Julia Lawall Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/sis/init301.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/sis/init301.c b/drivers/video/fbdev/sis/init301.c index a89e3cafd5ad..295e0dedaf1f 100644 --- a/drivers/video/fbdev/sis/init301.c +++ b/drivers/video/fbdev/sis/init301.c @@ -1714,7 +1714,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh SiS_Pr->PanelVCLKIdx315 = VCLK81_315; /* ? */ } else { SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 802; - SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRS = 112; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; SiS_Pr->PanelVCLKIdx300 = VCLK81_300; SiS_Pr->PanelVCLKIdx315 = VCLK81_315; -- GitLab From 58678a77029bc1f78f80f6f93da3d302d587f951 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 23 Aug 2014 20:33:28 +0200 Subject: [PATCH 0638/5088] video: fbdev: au1200fb: delete double assignment Delete successive assignments to the same location. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression i; @@ *i = ...; i = ...; // Signed-off-by: Julia Lawall Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/au1200fb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c index 40494dbdf519..18600d4e1b3f 100644 --- a/drivers/video/fbdev/au1200fb.c +++ b/drivers/video/fbdev/au1200fb.c @@ -1254,7 +1254,6 @@ static void set_global(u_int cmd, struct au1200_lcd_global_regs_t *pdata) pdata->brightness = 30; } divider = (lcd->pwmdiv & 0x3FFFF) + 1; - hi1 = (lcd->pwmhi >> 16) + 1; hi1 = (((pdata->brightness & 0xFF)+1) * divider >> 8); lcd->pwmhi &= 0xFFFF; lcd->pwmhi |= (hi1 << 16); -- GitLab From e720b82027b99482ea5d1001a69bdf2200e86b79 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 26 Aug 2014 19:01:42 +0530 Subject: [PATCH 0639/5088] ALSA: ctxfi: prink replacement as pr_* macros are more preffered over printk, so printk replaced with corresponding pr_err and pr_alert this patch will generate a warning from checkpatch for an unnecessary space before new line and has not been fixed as this patch is only for printk replacement. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctamixer.c | 4 ++-- sound/pci/ctxfi/ctatc.c | 20 ++++++++++---------- sound/pci/ctxfi/ctdaio.c | 2 +- sound/pci/ctxfi/cthw20k1.c | 10 +++++----- sound/pci/ctxfi/cthw20k2.c | 16 ++++++++-------- sound/pci/ctxfi/ctmixer.c | 4 ++-- sound/pci/ctxfi/ctresource.c | 12 ++++++------ sound/pci/ctxfi/ctsrc.c | 4 ++-- sound/pci/ctxfi/ctvmem.c | 4 ++-- sound/pci/ctxfi/xfi.c | 8 ++++---- 10 files changed, 42 insertions(+), 42 deletions(-) diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c index fee35cfc0c7f..fed6e6a57608 100644 --- a/sound/pci/ctxfi/ctamixer.c +++ b/sound/pci/ctxfi/ctamixer.c @@ -258,7 +258,7 @@ static int get_amixer_rsc(struct amixer_mgr *mgr, } spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n"); + pr_err("ctxfi: Can't meet AMIXER resource request!\n"); goto error; } @@ -411,7 +411,7 @@ static int get_sum_rsc(struct sum_mgr *mgr, } spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n"); + pr_err("ctxfi: Can't meet SUM resource request!\n"); goto error; } diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index af632bd08323..ce9061aee587 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -185,7 +185,7 @@ static unsigned int convert_format(snd_pcm_format_t snd_format) case SNDRV_PCM_FORMAT_FLOAT_LE: return SRC_SF_F32; default: - printk(KERN_ERR "ctxfi: not recognized snd format is %d \n", + pr_err("ctxfi: not recognized snd format is %d \n", snd_format); return SRC_SF_S16; } @@ -1282,7 +1282,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid) p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); if (p) { if (p->value < 0) { - printk(KERN_ERR "ctxfi: " + pr_err("ctxfi: " "Device %04x:%04x is black-listed\n", vendor_id, device_id); return -ENOENT; @@ -1315,7 +1315,7 @@ int ct_atc_create_alsa_devs(struct ct_atc *atc) err = alsa_dev_funcs[i].create(atc, i, alsa_dev_funcs[i].public_name); if (err) { - printk(KERN_ERR "ctxfi: " + pr_err("ctxfi: " "Creating alsa device %d failed!\n", i); return err; } @@ -1332,7 +1332,7 @@ static int atc_create_hw_devs(struct ct_atc *atc) err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw); if (err) { - printk(KERN_ERR "Failed to create hw obj!!!\n"); + pr_err("Failed to create hw obj!!!\n"); return err; } atc->hw = hw; @@ -1351,7 +1351,7 @@ static int atc_create_hw_devs(struct ct_atc *atc) err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); if (err) { - printk(KERN_ERR "ctxfi: " + pr_err("ctxfi: " "Failed to create rsc_mgr %d!!!\n", i); return err; } @@ -1399,7 +1399,7 @@ static int atc_get_resources(struct ct_atc *atc) err = daio_mgr->get_daio(daio_mgr, &da_desc, (struct daio **)&atc->daios[i]); if (err) { - printk(KERN_ERR "ctxfi: Failed to get DAIO " + pr_err("ctxfi: Failed to get DAIO " "resource %d!!!\n", i); return err; } @@ -1603,7 +1603,7 @@ static int atc_resume(struct ct_atc *atc) /* Do hardware resume. */ err = atc_hw_resume(atc); if (err < 0) { - printk(KERN_ERR "ctxfi: pci_enable_device failed, " + pr_err("ctxfi: pci_enable_device failed, " "disabling device\n"); snd_card_disconnect(atc->card); return err; @@ -1701,7 +1701,7 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, /* Find card model */ err = atc_identify_card(atc, ssid); if (err < 0) { - printk(KERN_ERR "ctatc: Card not recognised\n"); + pr_err("ctatc: Card not recognised\n"); goto error1; } @@ -1717,7 +1717,7 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); if (err) { - printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n"); + pr_err("ctxfi: Failed to create mixer obj!!!\n"); goto error1; } @@ -1744,6 +1744,6 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, error1: ct_atc_destroy(atc); - printk(KERN_ERR "ctxfi: Something wrong!!!\n"); + pr_err("ctxfi: Something wrong!!!\n"); return err; } diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 84f86bf63b8f..6f0654ea3630 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -541,7 +541,7 @@ static int get_daio_rsc(struct daio_mgr *mgr, err = daio_mgr_get_rsc(&mgr->mgr, desc->type); spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - printk(KERN_ERR "Can't meet DAIO resource request!\n"); + pr_err("Can't meet DAIO resource request!\n"); return err; } diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 6ac40beb49da..782641e77653 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1268,7 +1268,7 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) /* Set up device page table */ if ((~0UL) == info->vm_pgt_phys) { - printk(KERN_ERR "Wrong device page table page address!\n"); + pr_err("Wrong device page table page address!\n"); return -1; } @@ -1327,7 +1327,7 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr) mdelay(40); } if (i >= 3) { - printk(KERN_ALERT "PLL initialization failed!!!\n"); + pr_alert("PLL initialization failed!!!\n"); return -EBUSY; } @@ -1351,7 +1351,7 @@ static int hw_auto_init(struct hw *hw) break; } if (!get_field(gctl, GCTL_AID)) { - printk(KERN_ALERT "Card Auto-init failed!!!\n"); + pr_alert("Card Auto-init failed!!!\n"); return -EBUSY; } @@ -1911,7 +1911,7 @@ static int hw_card_start(struct hw *hw) /* Set DMA transfer mask */ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - printk(KERN_ERR "architecture does not support PCI " + pr_err("architecture does not support PCI " "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); err = -ENXIO; @@ -1942,7 +1942,7 @@ static int hw_card_start(struct hw *hw) err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, KBUILD_MODNAME, hw); if (err < 0) { - printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); + pr_err("XFi: Cannot get irq %d\n", pci->irq); goto error2; } hw->irq = pci->irq; diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index b1438861d38a..8a72fac929ca 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -1187,7 +1187,7 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121); hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); } else { - printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n"); + pr_alert("ctxfi: ERROR!!! Invalid sampling rate!!!\n"); return -EINVAL; } @@ -1246,7 +1246,7 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) /* Set up device page table */ if ((~0UL) == info->vm_pgt_phys) { - printk(KERN_ALERT "ctxfi: " + pr_alert("ctxfi: " "Wrong device page table page address!!!\n"); return -1; } @@ -1352,7 +1352,7 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr) break; } if (i >= 1000) { - printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n"); + pr_alert("ctxfi: PLL initialization failed!!!\n"); return -EBUSY; } @@ -1376,7 +1376,7 @@ static int hw_auto_init(struct hw *hw) break; } if (!get_field(gctl, GCTL_AID)) { - printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n"); + pr_alert("ctxfi: Card Auto-init failed!!!\n"); return -EBUSY; } @@ -1847,7 +1847,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) /* Initialize I2C */ err = hw20k2_i2c_init(hw, 0x1A, 1, 1); if (err < 0) { - printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n"); + pr_alert("ctxfi: Failure to acquire I2C!!!\n"); goto error; } @@ -1890,7 +1890,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), MAKE_WM8775_DATA(0x0A)); } else { - printk(KERN_ALERT "ctxfi: Invalid master sampling " + pr_alert("ctxfi: Invalid master sampling " "rate (msr %d)!!!\n", info->msr); err = -EINVAL; goto error; @@ -2034,7 +2034,7 @@ static int hw_card_start(struct hw *hw) /* Set DMA transfer mask */ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - printk(KERN_ERR "ctxfi: architecture does not support PCI " + pr_err("ctxfi: architecture does not support PCI " "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); err = -ENXIO; goto error1; @@ -2063,7 +2063,7 @@ static int hw_card_start(struct hw *hw) err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED, KBUILD_MODNAME, hw); if (err < 0) { - printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); + pr_err("XFi: Cannot get irq %d\n", pci->irq); goto error2; } hw->irq = pci->irq; diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index 48fe0e39c2be..8d986e45ecf6 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c @@ -854,7 +854,7 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer) for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum); if (err) { - printk(KERN_ERR "ctxfi:Failed to get sum resources for " + pr_err("ctxfi:Failed to get sum resources for " "front output!\n"); break; } @@ -869,7 +869,7 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer) for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer); if (err) { - printk(KERN_ERR "ctxfi:Failed to get amixer resources " + pr_err("ctxfi:Failed to get amixer resources " "for mixer obj!\n"); break; } diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c index 7dfaf67344d4..11ac934dcefd 100644 --- a/sound/pci/ctxfi/ctresource.c +++ b/sound/pci/ctxfi/ctresource.c @@ -162,13 +162,13 @@ int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) case DAIO: break; default: - printk(KERN_ERR + pr_err( "ctxfi: Invalid resource type value %d!\n", type); return -EINVAL; } if (err) { - printk(KERN_ERR + pr_err( "ctxfi: Failed to get resource control block!\n"); return err; } @@ -192,7 +192,7 @@ int rsc_uninit(struct rsc *rsc) case DAIO: break; default: - printk(KERN_ERR "ctxfi: " + pr_err("ctxfi: " "Invalid resource type value %d!\n", rsc->type); break; } @@ -235,14 +235,14 @@ int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, case SUM: break; default: - printk(KERN_ERR + pr_err( "ctxfi: Invalid resource type value %d!\n", type); err = -EINVAL; goto error; } if (err) { - printk(KERN_ERR + pr_err( "ctxfi: Failed to get manager control block!\n"); goto error; } @@ -286,7 +286,7 @@ int rsc_mgr_uninit(struct rsc_mgr *mgr) case SUM: break; default: - printk(KERN_ERR "ctxfi: " + pr_err("ctxfi: " "Invalid resource type value %d!\n", mgr->type); break; } diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index 6e77e86307c2..19df9b4ed800 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -431,7 +431,7 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - printk(KERN_ERR "ctxfi: Can't meet SRC resource request!\n"); + pr_err("ctxfi: Can't meet SRC resource request!\n"); return err; } @@ -739,7 +739,7 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr, } spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - printk(KERN_ERR "ctxfi: Can't meet SRCIMP resource request!\n"); + pr_err("ctxfi: Can't meet SRCIMP resource request!\n"); goto error1; } diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 6109490b83e8..5ea015bec793 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -36,7 +36,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size) size = CT_PAGE_ALIGN(size); if (size > vm->size) { - printk(KERN_ERR "ctxfi: Fail! No sufficient device virtual " + pr_err("ctxfi: Fail! No sufficient device virtual " "memory space available!\n"); return NULL; } @@ -132,7 +132,7 @@ ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) block = get_vm_block(vm, size); if (block == NULL) { - printk(KERN_ERR "ctxfi: No virtual memory block that is big " + pr_err("ctxfi: No virtual memory block that is big " "enough to allocate!\n"); return NULL; } diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 8f8b566a1b35..af8c49836000 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -76,16 +76,16 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (err) return err; if ((reference_rate != 48000) && (reference_rate != 44100)) { - printk(KERN_ERR "ctxfi: Invalid reference_rate value %u!!!\n", + pr_err("ctxfi: Invalid reference_rate value %u!!!\n", reference_rate); - printk(KERN_ERR "ctxfi: The valid values for reference_rate " + pr_err("ctxfi: The valid values for reference_rate " "are 48000 and 44100, Value 48000 is assumed.\n"); reference_rate = 48000; } if ((multiple != 1) && (multiple != 2) && (multiple != 4)) { - printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n", + pr_err("ctxfi: Invalid multiple value %u!!!\n", multiple); - printk(KERN_ERR "ctxfi: The valid values for multiple are " + pr_err("ctxfi: The valid values for multiple are " "1, 2 and 4, Value 2 is assumed.\n"); multiple = 2; } -- GitLab From 62afa853cb91288e85a8da6351bd29d798402308 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 26 Aug 2014 19:01:43 +0530 Subject: [PATCH 0640/5088] ALSA: ctxfi: fix broken user-visible string as broken user-visible strings breaks the ability to grep for them , so this patch fixes the broken user-visible strings Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctatc.c | 18 +++++++----------- sound/pci/ctxfi/cthw20k1.c | 3 +-- sound/pci/ctxfi/cthw20k2.c | 11 +++++------ sound/pci/ctxfi/ctmixer.c | 6 ++---- sound/pci/ctxfi/ctresource.c | 20 ++++++++------------ sound/pci/ctxfi/ctvmem.c | 6 ++---- sound/pci/ctxfi/xfi.c | 6 ++---- 7 files changed, 27 insertions(+), 43 deletions(-) diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index ce9061aee587..d92a08c7a39c 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -185,7 +185,7 @@ static unsigned int convert_format(snd_pcm_format_t snd_format) case SNDRV_PCM_FORMAT_FLOAT_LE: return SRC_SF_F32; default: - pr_err("ctxfi: not recognized snd format is %d \n", + pr_err("ctxfi: not recognized snd format is %d\n", snd_format); return SRC_SF_S16; } @@ -1282,8 +1282,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid) p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); if (p) { if (p->value < 0) { - pr_err("ctxfi: " - "Device %04x:%04x is black-listed\n", + pr_err("ctxfi: Device %04x:%04x is black-listed\n", vendor_id, device_id); return -ENOENT; } @@ -1315,8 +1314,7 @@ int ct_atc_create_alsa_devs(struct ct_atc *atc) err = alsa_dev_funcs[i].create(atc, i, alsa_dev_funcs[i].public_name); if (err) { - pr_err("ctxfi: " - "Creating alsa device %d failed!\n", i); + pr_err("ctxfi: Creating alsa device %d failed!\n", i); return err; } } @@ -1351,8 +1349,7 @@ static int atc_create_hw_devs(struct ct_atc *atc) err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); if (err) { - pr_err("ctxfi: " - "Failed to create rsc_mgr %d!!!\n", i); + pr_err("ctxfi: Failed to create rsc_mgr %d!!!\n", i); return err; } } @@ -1399,8 +1396,8 @@ static int atc_get_resources(struct ct_atc *atc) err = daio_mgr->get_daio(daio_mgr, &da_desc, (struct daio **)&atc->daios[i]); if (err) { - pr_err("ctxfi: Failed to get DAIO " - "resource %d!!!\n", i); + pr_err("ctxfi: Failed to get DAIO resource %d!!!\n", + i); return err; } atc->n_daio++; @@ -1603,8 +1600,7 @@ static int atc_resume(struct ct_atc *atc) /* Do hardware resume. */ err = atc_hw_resume(atc); if (err < 0) { - pr_err("ctxfi: pci_enable_device failed, " - "disabling device\n"); + pr_err("ctxfi: pci_enable_device failed, disabling device\n"); snd_card_disconnect(atc->card); return err; } diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 782641e77653..71d496f780e3 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1911,8 +1911,7 @@ static int hw_card_start(struct hw *hw) /* Set DMA transfer mask */ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - pr_err("architecture does not support PCI " - "busmaster DMA with mask 0x%llx\n", + pr_err("architecture does not support PCI busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); err = -ENXIO; goto error1; diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 8a72fac929ca..df2d8c5eb926 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -1246,8 +1246,7 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) /* Set up device page table */ if ((~0UL) == info->vm_pgt_phys) { - pr_alert("ctxfi: " - "Wrong device page table page address!!!\n"); + pr_alert("ctxfi: Wrong device page table page address!!!\n"); return -1; } @@ -1890,8 +1889,8 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), MAKE_WM8775_DATA(0x0A)); } else { - pr_alert("ctxfi: Invalid master sampling " - "rate (msr %d)!!!\n", info->msr); + pr_alert("ctxfi: Invalid master sampling rate (msr %d)!!!\n", + info->msr); err = -EINVAL; goto error; } @@ -2034,8 +2033,8 @@ static int hw_card_start(struct hw *hw) /* Set DMA transfer mask */ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - pr_err("ctxfi: architecture does not support PCI " - "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); + pr_err("ctxfi: architecture does not support PCI busmaster DMA with mask 0x%llx\n", + CT_XFI_DMA_MASK); err = -ENXIO; goto error1; } diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index 8d986e45ecf6..017fa91706d4 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c @@ -854,8 +854,7 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer) for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum); if (err) { - pr_err("ctxfi:Failed to get sum resources for " - "front output!\n"); + pr_err("ctxfi:Failed to get sum resources for front output!\n"); break; } mixer->sums[i] = sum; @@ -869,8 +868,7 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer) for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer); if (err) { - pr_err("ctxfi:Failed to get amixer resources " - "for mixer obj!\n"); + pr_err("ctxfi:Failed to get amixer resources for mixer obj!\n"); break; } mixer->amixers[i] = amixer; diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c index 11ac934dcefd..e49d2be1bfd4 100644 --- a/sound/pci/ctxfi/ctresource.c +++ b/sound/pci/ctxfi/ctresource.c @@ -162,14 +162,12 @@ int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) case DAIO: break; default: - pr_err( - "ctxfi: Invalid resource type value %d!\n", type); + pr_err("ctxfi: Invalid resource type value %d!\n", type); return -EINVAL; } if (err) { - pr_err( - "ctxfi: Failed to get resource control block!\n"); + pr_err("ctxfi: Failed to get resource control block!\n"); return err; } @@ -192,8 +190,8 @@ int rsc_uninit(struct rsc *rsc) case DAIO: break; default: - pr_err("ctxfi: " - "Invalid resource type value %d!\n", rsc->type); + pr_err("ctxfi: Invalid resource type value %d!\n", + rsc->type); break; } @@ -235,15 +233,13 @@ int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, case SUM: break; default: - pr_err( - "ctxfi: Invalid resource type value %d!\n", type); + pr_err("ctxfi: Invalid resource type value %d!\n", type); err = -EINVAL; goto error; } if (err) { - pr_err( - "ctxfi: Failed to get manager control block!\n"); + pr_err("ctxfi: Failed to get manager control block!\n"); goto error; } @@ -286,8 +282,8 @@ int rsc_mgr_uninit(struct rsc_mgr *mgr) case SUM: break; default: - pr_err("ctxfi: " - "Invalid resource type value %d!\n", mgr->type); + pr_err("ctxfi: Invalid resource type value %d!\n", + mgr->type); break; } diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 5ea015bec793..38163f52dd5f 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -36,8 +36,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size) size = CT_PAGE_ALIGN(size); if (size > vm->size) { - pr_err("ctxfi: Fail! No sufficient device virtual " - "memory space available!\n"); + pr_err("ctxfi: Fail! No sufficient device virtual memory space available!\n"); return NULL; } @@ -132,8 +131,7 @@ ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) block = get_vm_block(vm, size); if (block == NULL) { - pr_err("ctxfi: No virtual memory block that is big " - "enough to allocate!\n"); + pr_err("ctxfi: No virtual memory block that is big enough to allocate!\n"); return NULL; } diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index af8c49836000..35e85ba80656 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -78,15 +78,13 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if ((reference_rate != 48000) && (reference_rate != 44100)) { pr_err("ctxfi: Invalid reference_rate value %u!!!\n", reference_rate); - pr_err("ctxfi: The valid values for reference_rate " - "are 48000 and 44100, Value 48000 is assumed.\n"); + pr_err("ctxfi: The valid values for reference_rate are 48000 and 44100, Value 48000 is assumed.\n"); reference_rate = 48000; } if ((multiple != 1) && (multiple != 2) && (multiple != 4)) { pr_err("ctxfi: Invalid multiple value %u!!!\n", multiple); - pr_err("ctxfi: The valid values for multiple are " - "1, 2 and 4, Value 2 is assumed.\n"); + pr_err("ctxfi: The valid values for multiple are 1, 2 and 4, Value 2 is assumed.\n"); multiple = 2; } err = ct_atc_create(card, pci, reference_rate, multiple, -- GitLab From 2d0871396995139b37f9ceb153c8b07589148343 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Fri, 22 Aug 2014 15:51:03 +0200 Subject: [PATCH 0641/5088] builddeb: put the dbg files into the correct directory Since the conversion of objtree to use relative pathnames (commit 7e1c04779e, "kbuild: Use relative path for $(objtree)"), the debug info files have been ending up in /debian/dbgtmp/ in the regular linux-image package instead of the debug files package. Fix up the paths so that the debug files end up in the -dbg package. This is based on a similar patch by Darrick. Reported-and-tested-by: "Darrick J. Wong" Signed-off-by: Michal Marek --- scripts/package/builddeb | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 35d5a5877d04..7c0e6e46905d 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -152,18 +152,16 @@ if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then rmdir "$tmpdir/lib/modules/$version" fi if [ -n "$BUILD_DEBUG" ] ; then - ( - cd $tmpdir - for module in $(find lib/modules/ -name *.ko); do - mkdir -p $(dirname $dbg_dir/usr/lib/debug/$module) - # only keep debug symbols in the debug file - $OBJCOPY --only-keep-debug $module $dbg_dir/usr/lib/debug/$module - # strip original module from debug symbols - $OBJCOPY --strip-debug $module - # then add a link to those - $OBJCOPY --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $module - done - ) + for module in $(find $tmpdir/lib/modules/ -name *.ko -printf '%P\n'); do + module=lib/modules/$module + mkdir -p $(dirname $dbg_dir/usr/lib/debug/$module) + # only keep debug symbols in the debug file + $OBJCOPY --only-keep-debug $tmpdir/$module $dbg_dir/usr/lib/debug/$module + # strip original module from debug symbols + $OBJCOPY --strip-debug $tmpdir/$module + # then add a link to those + $OBJCOPY --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $tmpdir/$module + done fi fi -- GitLab From bb964a92ce70ac2039115edd019aa5eef8faa6bb Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:24 -0500 Subject: [PATCH 0642/5088] kernel misc: Replace __get_cpu_var uses Replace uses of __get_cpu_var for address calculation with this_cpu_ptr. Cc: akpm@linux-foundation.org Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- kernel/printk/printk.c | 4 ++-- kernel/smp.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index e04c455a0e38..960fbfc6cd0a 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2628,7 +2628,7 @@ void wake_up_klogd(void) preempt_disable(); if (waitqueue_active(&log_wait)) { this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); - irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); + irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); } preempt_enable(); } @@ -2644,7 +2644,7 @@ int printk_deferred(const char *fmt, ...) va_end(args); __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT); - irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); + irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); preempt_enable(); return r; diff --git a/kernel/smp.c b/kernel/smp.c index aff8aa14f547..af24183fe6bb 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -164,7 +164,7 @@ static int generic_exec_single(int cpu, struct call_single_data *csd, if (!csd) { csd = &csd_stack; if (!wait) - csd = &__get_cpu_var(csd_data); + csd = this_cpu_ptr(&csd_data); } csd_lock(csd); @@ -229,7 +229,7 @@ static void flush_smp_call_function_queue(bool warn_cpu_offline) WARN_ON(!irqs_disabled()); - head = &__get_cpu_var(call_single_queue); + head = this_cpu_ptr(&call_single_queue); entry = llist_del_all(head); entry = llist_reverse_order(entry); @@ -419,7 +419,7 @@ void smp_call_function_many(const struct cpumask *mask, return; } - cfd = &__get_cpu_var(cfd_data); + cfd = this_cpu_ptr(&cfd_data); cpumask_and(cfd->cpumask, mask, cpu_online_mask); cpumask_clear_cpu(this_cpu, cfd->cpumask); -- GitLab From 22127e93c587afa01e4f7225d2d1cf1d26ae7dfe Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:25 -0500 Subject: [PATCH 0643/5088] time: Replace __get_cpu_var uses Convert uses of __get_cpu_var for creating a address from a percpu offset to this_cpu_ptr. The two cases where get_cpu_var is used to actually access a percpu variable are changed to use this_cpu_read/raw_cpu_read. Reviewed-by: Thomas Gleixner Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/clocksource/dummy_timer.c | 2 +- kernel/irq_work.c | 12 ++++++------ kernel/sched/clock.c | 2 +- kernel/softirq.c | 4 ++-- kernel/time/hrtimer.c | 6 +++--- kernel/time/tick-broadcast.c | 2 +- kernel/time/tick-common.c | 6 +++--- kernel/time/tick-oneshot.c | 2 +- kernel/time/tick-sched.c | 20 ++++++++++---------- kernel/time/timer.c | 2 +- 10 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c index ad3572541728..31990600fcff 100644 --- a/drivers/clocksource/dummy_timer.c +++ b/drivers/clocksource/dummy_timer.c @@ -28,7 +28,7 @@ static void dummy_timer_set_mode(enum clock_event_mode mode, static void dummy_timer_setup(void) { int cpu = smp_processor_id(); - struct clock_event_device *evt = __this_cpu_ptr(&dummy_timer_evt); + struct clock_event_device *evt = raw_cpu_ptr(&dummy_timer_evt); evt->name = "dummy_timer"; evt->features = CLOCK_EVT_FEAT_PERIODIC | diff --git a/kernel/irq_work.c b/kernel/irq_work.c index e6bcbe756663..345d19edcdae 100644 --- a/kernel/irq_work.c +++ b/kernel/irq_work.c @@ -95,11 +95,11 @@ bool irq_work_queue(struct irq_work *work) /* If the work is "lazy", handle it from next tick if any */ if (work->flags & IRQ_WORK_LAZY) { - if (llist_add(&work->llnode, &__get_cpu_var(lazy_list)) && + if (llist_add(&work->llnode, this_cpu_ptr(&lazy_list)) && tick_nohz_tick_stopped()) arch_irq_work_raise(); } else { - if (llist_add(&work->llnode, &__get_cpu_var(raised_list))) + if (llist_add(&work->llnode, this_cpu_ptr(&raised_list))) arch_irq_work_raise(); } @@ -113,8 +113,8 @@ bool irq_work_needs_cpu(void) { struct llist_head *raised, *lazy; - raised = &__get_cpu_var(raised_list); - lazy = &__get_cpu_var(lazy_list); + raised = this_cpu_ptr(&raised_list); + lazy = this_cpu_ptr(&lazy_list); if (llist_empty(raised) && llist_empty(lazy)) return false; @@ -166,8 +166,8 @@ static void irq_work_run_list(struct llist_head *list) */ void irq_work_run(void) { - irq_work_run_list(&__get_cpu_var(raised_list)); - irq_work_run_list(&__get_cpu_var(lazy_list)); + irq_work_run_list(this_cpu_ptr(&raised_list)); + irq_work_run_list(this_cpu_ptr(&lazy_list)); } EXPORT_SYMBOL_GPL(irq_work_run); diff --git a/kernel/sched/clock.c b/kernel/sched/clock.c index 3ef6451e972e..c27e4f8f4879 100644 --- a/kernel/sched/clock.c +++ b/kernel/sched/clock.c @@ -134,7 +134,7 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct sched_clock_data, sched_clock_data); static inline struct sched_clock_data *this_scd(void) { - return &__get_cpu_var(sched_clock_data); + return this_cpu_ptr(&sched_clock_data); } static inline struct sched_clock_data *cpu_sdc(int cpu) diff --git a/kernel/softirq.c b/kernel/softirq.c index 5918d227730f..2d44b5714fe6 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -485,7 +485,7 @@ static void tasklet_action(struct softirq_action *a) local_irq_disable(); list = __this_cpu_read(tasklet_vec.head); __this_cpu_write(tasklet_vec.head, NULL); - __this_cpu_write(tasklet_vec.tail, &__get_cpu_var(tasklet_vec).head); + __this_cpu_write(tasklet_vec.tail, this_cpu_ptr(&tasklet_vec.head)); local_irq_enable(); while (list) { @@ -521,7 +521,7 @@ static void tasklet_hi_action(struct softirq_action *a) local_irq_disable(); list = __this_cpu_read(tasklet_hi_vec.head); __this_cpu_write(tasklet_hi_vec.head, NULL); - __this_cpu_write(tasklet_hi_vec.tail, &__get_cpu_var(tasklet_hi_vec).head); + __this_cpu_write(tasklet_hi_vec.tail, this_cpu_ptr(&tasklet_hi_vec.head)); local_irq_enable(); while (list) { diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 1c2fe7de2842..5f2229ba53d6 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1144,7 +1144,7 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, memset(timer, 0, sizeof(struct hrtimer)); - cpu_base = &__raw_get_cpu_var(hrtimer_bases); + cpu_base = raw_cpu_ptr(&hrtimer_bases); if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS) clock_id = CLOCK_MONOTONIC; @@ -1187,7 +1187,7 @@ int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp) struct hrtimer_cpu_base *cpu_base; int base = hrtimer_clockid_to_base(which_clock); - cpu_base = &__raw_get_cpu_var(hrtimer_bases); + cpu_base = raw_cpu_ptr(&hrtimer_bases); *tp = ktime_to_timespec(cpu_base->clock_base[base].resolution); return 0; @@ -1376,7 +1376,7 @@ static void __hrtimer_peek_ahead_timers(void) if (!hrtimer_hres_active()) return; - td = &__get_cpu_var(tick_cpu_device); + td = this_cpu_ptr(&tick_cpu_device); if (td && td->evtdev) hrtimer_interrupt(td->evtdev); } diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 64c5990fd500..066f0ec05e48 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -554,7 +554,7 @@ int tick_resume_broadcast_oneshot(struct clock_event_device *bc) void tick_check_oneshot_broadcast_this_cpu(void) { if (cpumask_test_cpu(smp_processor_id(), tick_broadcast_oneshot_mask)) { - struct tick_device *td = &__get_cpu_var(tick_cpu_device); + struct tick_device *td = this_cpu_ptr(&tick_cpu_device); /* * We might be in the middle of switching over from diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 0a0608edeb26..decfb5f6edb0 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -224,7 +224,7 @@ static void tick_setup_device(struct tick_device *td, void tick_install_replacement(struct clock_event_device *newdev) { - struct tick_device *td = &__get_cpu_var(tick_cpu_device); + struct tick_device *td = this_cpu_ptr(&tick_cpu_device); int cpu = smp_processor_id(); clockevents_exchange_device(td->evtdev, newdev); @@ -374,14 +374,14 @@ void tick_shutdown(unsigned int *cpup) void tick_suspend(void) { - struct tick_device *td = &__get_cpu_var(tick_cpu_device); + struct tick_device *td = this_cpu_ptr(&tick_cpu_device); clockevents_shutdown(td->evtdev); } void tick_resume(void) { - struct tick_device *td = &__get_cpu_var(tick_cpu_device); + struct tick_device *td = this_cpu_ptr(&tick_cpu_device); int broadcast = tick_resume_broadcast(); clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_RESUME); diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 824109060a33..7ce740e78e1b 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c @@ -59,7 +59,7 @@ void tick_setup_oneshot(struct clock_event_device *newdev, */ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) { - struct tick_device *td = &__get_cpu_var(tick_cpu_device); + struct tick_device *td = this_cpu_ptr(&tick_cpu_device); struct clock_event_device *dev = td->evtdev; if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) || diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 99aa6ee3908f..73f90932282b 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -205,7 +205,7 @@ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now); */ void __tick_nohz_full_check(void) { - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); if (tick_nohz_full_cpu(smp_processor_id())) { if (ts->tick_stopped && !is_idle_task(current)) { @@ -545,7 +545,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, unsigned long seq, last_jiffies, next_jiffies, delta_jiffies; ktime_t last_update, expires, ret = { .tv64 = 0 }; unsigned long rcu_delta_jiffies; - struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; + struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); u64 time_delta; time_delta = timekeeping_max_deferment(); @@ -813,7 +813,7 @@ void tick_nohz_idle_enter(void) local_irq_disable(); - ts = &__get_cpu_var(tick_cpu_sched); + ts = this_cpu_ptr(&tick_cpu_sched); ts->inidle = 1; __tick_nohz_idle_enter(ts); @@ -831,7 +831,7 @@ EXPORT_SYMBOL_GPL(tick_nohz_idle_enter); */ void tick_nohz_irq_exit(void) { - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); if (ts->inidle) __tick_nohz_idle_enter(ts); @@ -846,7 +846,7 @@ void tick_nohz_irq_exit(void) */ ktime_t tick_nohz_get_sleep_length(void) { - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); return ts->sleep_length; } @@ -959,7 +959,7 @@ static int tick_nohz_reprogram(struct tick_sched *ts, ktime_t now) */ static void tick_nohz_handler(struct clock_event_device *dev) { - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); struct pt_regs *regs = get_irq_regs(); ktime_t now = ktime_get(); @@ -979,7 +979,7 @@ static void tick_nohz_handler(struct clock_event_device *dev) */ static void tick_nohz_switch_to_nohz(void) { - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); ktime_t next; if (!tick_nohz_enabled) @@ -1115,7 +1115,7 @@ early_param("skew_tick", skew_tick); */ void tick_setup_sched_timer(void) { - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); ktime_t now = ktime_get(); /* @@ -1184,7 +1184,7 @@ void tick_clock_notify(void) */ void tick_oneshot_notify(void) { - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); set_bit(0, &ts->check_clocks); } @@ -1199,7 +1199,7 @@ void tick_oneshot_notify(void) */ int tick_check_oneshot_change(int allow_nohz) { - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); if (!test_and_clear_bit(0, &ts->check_clocks)) return 0; diff --git a/kernel/time/timer.c b/kernel/time/timer.c index aca5dfe2fa3d..04d8ed8399b0 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -655,7 +655,7 @@ static inline void debug_assert_init(struct timer_list *timer) static void do_init_timer(struct timer_list *timer, unsigned int flags, const char *name, struct lock_class_key *key) { - struct tvec_base *base = __raw_get_cpu_var(tvec_bases); + struct tvec_base *base = raw_cpu_read(tvec_bases); timer->entry.next = NULL; timer->base = (void *)((unsigned long)base | flags); -- GitLab From dc5df73b3afffc8d042dadffc1c959008b2c1163 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:26 -0500 Subject: [PATCH 0644/5088] time: Convert a bunch of &__get_cpu_var introduced in the 3.16 merge period Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- kernel/time/hrtimer.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 5f2229ba53d6..a50600d87fb7 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -558,7 +558,7 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal) static int hrtimer_reprogram(struct hrtimer *timer, struct hrtimer_clock_base *base) { - struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); ktime_t expires = ktime_sub(hrtimer_get_expires(timer), base->offset); int res; @@ -629,7 +629,7 @@ static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) */ static void retrigger_next_event(void *arg) { - struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases); + struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases); if (!hrtimer_hres_active()) return; @@ -903,7 +903,7 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) */ debug_deactivate(timer); timer_stats_hrtimer_clear_start_info(timer); - reprogram = base->cpu_base == &__get_cpu_var(hrtimer_bases); + reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); /* * We must preserve the CALLBACK state flag here, * otherwise we could move the timer base in @@ -963,7 +963,7 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, * on dynticks target. */ wake_up_nohz_cpu(new_base->cpu_base->cpu); - } else if (new_base->cpu_base == &__get_cpu_var(hrtimer_bases) && + } else if (new_base->cpu_base == this_cpu_ptr(&hrtimer_bases) && hrtimer_reprogram(timer, new_base)) { /* * Only allow reprogramming if the new base is on this CPU. @@ -1103,7 +1103,7 @@ EXPORT_SYMBOL_GPL(hrtimer_get_remaining); */ ktime_t hrtimer_get_next_event(void) { - struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); struct hrtimer_clock_base *base = cpu_base->clock_base; ktime_t delta, mindelta = { .tv64 = KTIME_MAX }; unsigned long flags; @@ -1242,7 +1242,7 @@ static void __run_hrtimer(struct hrtimer *timer, ktime_t *now) */ void hrtimer_interrupt(struct clock_event_device *dev) { - struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); ktime_t expires_next, now, entry_time, delta; int i, retries = 0; @@ -1440,7 +1440,7 @@ void hrtimer_run_pending(void) void hrtimer_run_queues(void) { struct timerqueue_node *node; - struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); struct hrtimer_clock_base *base; int index, gettime = 1; @@ -1679,7 +1679,7 @@ static void migrate_hrtimers(int scpu) local_irq_disable(); old_base = &per_cpu(hrtimer_bases, scpu); - new_base = &__get_cpu_var(hrtimer_bases); + new_base = this_cpu_ptr(&hrtimer_bases); /* * The caller is globally serialized and nobody else * takes two locks at once, deadlock is not possible. -- GitLab From 4a32fea9d78f2d2315c0072757b197d5a304dc8b Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:27 -0500 Subject: [PATCH 0645/5088] scheduler: Replace __get_cpu_var with this_cpu_ptr Convert all uses of __get_cpu_var for address calculation to use this_cpu_ptr instead. [Uses of __get_cpu_var with cpumask_var_t are no longer handled by this patch] Cc: Peter Zijlstra Acked-by: Ingo Molnar Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- include/linux/kernel_stat.h | 4 ++-- kernel/events/callchain.c | 4 ++-- kernel/events/core.c | 24 ++++++++++++------------ kernel/sched/sched.h | 4 ++-- kernel/taskstats.c | 2 +- kernel/time/tick-sched.c | 4 ++-- kernel/user-return-notifier.c | 4 ++-- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index ecbc52f9ff77..8422b4ed6882 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -44,8 +44,8 @@ DECLARE_PER_CPU(struct kernel_stat, kstat); DECLARE_PER_CPU(struct kernel_cpustat, kernel_cpustat); /* Must have preemption disabled for this to be meaningful. */ -#define kstat_this_cpu (&__get_cpu_var(kstat)) -#define kcpustat_this_cpu (&__get_cpu_var(kernel_cpustat)) +#define kstat_this_cpu this_cpu_ptr(&kstat) +#define kcpustat_this_cpu this_cpu_ptr(&kernel_cpustat) #define kstat_cpu(cpu) per_cpu(kstat, cpu) #define kcpustat_cpu(cpu) per_cpu(kernel_cpustat, cpu) diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index 97b67df8fbfe..c4f63e68a35c 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c @@ -137,7 +137,7 @@ static struct perf_callchain_entry *get_callchain_entry(int *rctx) int cpu; struct callchain_cpus_entries *entries; - *rctx = get_recursion_context(__get_cpu_var(callchain_recursion)); + *rctx = get_recursion_context(this_cpu_ptr(callchain_recursion)); if (*rctx == -1) return NULL; @@ -153,7 +153,7 @@ static struct perf_callchain_entry *get_callchain_entry(int *rctx) static void put_callchain_entry(int rctx) { - put_recursion_context(__get_cpu_var(callchain_recursion), rctx); + put_recursion_context(this_cpu_ptr(callchain_recursion), rctx); } struct perf_callchain_entry * diff --git a/kernel/events/core.c b/kernel/events/core.c index 1cf24b3e42ec..4d44e40a0483 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -239,7 +239,7 @@ static void perf_duration_warn(struct irq_work *w) u64 avg_local_sample_len; u64 local_samples_len; - local_samples_len = __get_cpu_var(running_sample_length); + local_samples_len = __this_cpu_read(running_sample_length); avg_local_sample_len = local_samples_len/NR_ACCUMULATED_SAMPLES; printk_ratelimited(KERN_WARNING @@ -261,10 +261,10 @@ void perf_sample_event_took(u64 sample_len_ns) return; /* decay the counter by 1 average sample */ - local_samples_len = __get_cpu_var(running_sample_length); + local_samples_len = __this_cpu_read(running_sample_length); local_samples_len -= local_samples_len/NR_ACCUMULATED_SAMPLES; local_samples_len += sample_len_ns; - __get_cpu_var(running_sample_length) = local_samples_len; + __this_cpu_write(running_sample_length, local_samples_len); /* * note: this will be biased artifically low until we have @@ -877,7 +877,7 @@ static DEFINE_PER_CPU(struct list_head, rotation_list); static void perf_pmu_rotate_start(struct pmu *pmu) { struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); - struct list_head *head = &__get_cpu_var(rotation_list); + struct list_head *head = this_cpu_ptr(&rotation_list); WARN_ON(!irqs_disabled()); @@ -2389,7 +2389,7 @@ void __perf_event_task_sched_out(struct task_struct *task, * to check if we have to switch out PMU state. * cgroup event are system-wide mode only */ - if (atomic_read(&__get_cpu_var(perf_cgroup_events))) + if (atomic_read(this_cpu_ptr(&perf_cgroup_events))) perf_cgroup_sched_out(task, next); } @@ -2632,11 +2632,11 @@ void __perf_event_task_sched_in(struct task_struct *prev, * to check if we have to switch in PMU state. * cgroup event are system-wide mode only */ - if (atomic_read(&__get_cpu_var(perf_cgroup_events))) + if (atomic_read(this_cpu_ptr(&perf_cgroup_events))) perf_cgroup_sched_in(prev, task); /* check for system-wide branch_stack events */ - if (atomic_read(&__get_cpu_var(perf_branch_stack_events))) + if (atomic_read(this_cpu_ptr(&perf_branch_stack_events))) perf_branch_stack_sched_in(prev, task); } @@ -2891,7 +2891,7 @@ bool perf_event_can_stop_tick(void) void perf_event_task_tick(void) { - struct list_head *head = &__get_cpu_var(rotation_list); + struct list_head *head = this_cpu_ptr(&rotation_list); struct perf_cpu_context *cpuctx, *tmp; struct perf_event_context *ctx; int throttled; @@ -5671,7 +5671,7 @@ static void do_perf_sw_event(enum perf_type_id type, u32 event_id, struct perf_sample_data *data, struct pt_regs *regs) { - struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); + struct swevent_htable *swhash = this_cpu_ptr(&swevent_htable); struct perf_event *event; struct hlist_head *head; @@ -5690,7 +5690,7 @@ static void do_perf_sw_event(enum perf_type_id type, u32 event_id, int perf_swevent_get_recursion_context(void) { - struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); + struct swevent_htable *swhash = this_cpu_ptr(&swevent_htable); return get_recursion_context(swhash->recursion); } @@ -5698,7 +5698,7 @@ EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context); inline void perf_swevent_put_recursion_context(int rctx) { - struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); + struct swevent_htable *swhash = this_cpu_ptr(&swevent_htable); put_recursion_context(swhash->recursion, rctx); } @@ -5727,7 +5727,7 @@ static void perf_swevent_read(struct perf_event *event) static int perf_swevent_add(struct perf_event *event, int flags) { - struct swevent_htable *swhash = &__get_cpu_var(swevent_htable); + struct swevent_htable *swhash = this_cpu_ptr(&swevent_htable); struct hw_perf_event *hwc = &event->hw; struct hlist_head *head; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 579712f4e9d5..77d92f8130e8 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -650,10 +650,10 @@ static inline int cpu_of(struct rq *rq) DECLARE_PER_CPU(struct rq, runqueues); #define cpu_rq(cpu) (&per_cpu(runqueues, (cpu))) -#define this_rq() (&__get_cpu_var(runqueues)) +#define this_rq() this_cpu_ptr(&runqueues) #define task_rq(p) cpu_rq(task_cpu(p)) #define cpu_curr(cpu) (cpu_rq(cpu)->curr) -#define raw_rq() (&__raw_get_cpu_var(runqueues)) +#define raw_rq() raw_cpu_ptr(&runqueues) static inline u64 rq_clock(struct rq *rq) { diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 13d2f7cd65db..b312fcc73024 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -638,7 +638,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead) fill_tgid_exit(tsk); } - listeners = __this_cpu_ptr(&listener_array); + listeners = raw_cpu_ptr(&listener_array); if (list_empty(&listeners->list)) return; diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 73f90932282b..3cadc112519f 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -924,7 +924,7 @@ static void tick_nohz_account_idle_ticks(struct tick_sched *ts) */ void tick_nohz_idle_exit(void) { - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); ktime_t now; local_irq_disable(); @@ -1041,7 +1041,7 @@ static void tick_nohz_kick_tick(struct tick_sched *ts, ktime_t now) static inline void tick_nohz_irq_enter(void) { - struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); + struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); ktime_t now; if (!ts->idle_active && !ts->tick_stopped) diff --git a/kernel/user-return-notifier.c b/kernel/user-return-notifier.c index 394f70b17162..9586b670a5b2 100644 --- a/kernel/user-return-notifier.c +++ b/kernel/user-return-notifier.c @@ -14,7 +14,7 @@ static DEFINE_PER_CPU(struct hlist_head, return_notifier_list); void user_return_notifier_register(struct user_return_notifier *urn) { set_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY); - hlist_add_head(&urn->link, &__get_cpu_var(return_notifier_list)); + hlist_add_head(&urn->link, this_cpu_ptr(&return_notifier_list)); } EXPORT_SYMBOL_GPL(user_return_notifier_register); @@ -25,7 +25,7 @@ EXPORT_SYMBOL_GPL(user_return_notifier_register); void user_return_notifier_unregister(struct user_return_notifier *urn) { hlist_del(&urn->link); - if (hlist_empty(&__get_cpu_var(return_notifier_list))) + if (hlist_empty(this_cpu_ptr(&return_notifier_list))) clear_tsk_thread_flag(current, TIF_USER_RETURN_NOTIFY); } EXPORT_SYMBOL_GPL(user_return_notifier_unregister); -- GitLab From a0b6bc63a20a91faef0127cc61cca6d06ee737df Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:28 -0500 Subject: [PATCH 0646/5088] block: Replace __this_cpu_ptr with raw_cpu_ptr __this_cpu_ptr is being phased out use raw_cpu_ptr instead which was introduced in 3.15-rc1. Cc: Jens Axboe Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- fs/ext4/mballoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 956027711faf..33ccdcf51a9e 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -4129,7 +4129,7 @@ static void ext4_mb_group_or_file(struct ext4_allocation_context *ac) * per cpu locality group is to reduce the contention between block * request from multiple CPUs. */ - ac->ac_lg = __this_cpu_ptr(sbi->s_locality_groups); + ac->ac_lg = raw_cpu_ptr(sbi->s_locality_groups); /* we're going to use group allocation */ ac->ac_flags |= EXT4_MB_HINT_GROUP_ALLOC; -- GitLab From 1b2a1a7e8ad1144dc3f676f2651cb84e01548d59 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:29 -0500 Subject: [PATCH 0647/5088] drivers/char/random: Replace __get_cpu_var uses A single case of using __get_cpu_var for address calculation. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/char/random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index c18d41db83d8..82759cef9043 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -874,7 +874,7 @@ static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs) void add_interrupt_randomness(int irq, int irq_flags) { struct entropy_store *r; - struct fast_pool *fast_pool = &__get_cpu_var(irq_randomness); + struct fast_pool *fast_pool = this_cpu_ptr(&irq_randomness); struct pt_regs *regs = get_irq_regs(); unsigned long now = jiffies; cycles_t cycles = random_get_entropy(); -- GitLab From 229b6863b2cf9514f08e468fea586bc195ebcf50 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:30 -0500 Subject: [PATCH 0648/5088] drivers/cpuidle: Replace __get_cpu_var uses for address calculation All of these are for address calculation. Replace with this_cpu_ptr(). Cc: Daniel Lezcano Cc: linux-pm@vger.kernel.org Acked-by: Rafael J. Wysocki [cpufreq changes] Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/cpuidle/governors/ladder.c | 4 ++-- drivers/cpuidle/governors/menu.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index 044ee0df5871..06b57c4c4d80 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -66,7 +66,7 @@ static inline void ladder_do_selection(struct ladder_device *ldev, static int ladder_select_state(struct cpuidle_driver *drv, struct cpuidle_device *dev) { - struct ladder_device *ldev = &__get_cpu_var(ladder_devices); + struct ladder_device *ldev = this_cpu_ptr(&ladder_devices); struct ladder_device_state *last_state; int last_residency, last_idx = ldev->last_state_idx; int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); @@ -170,7 +170,7 @@ static int ladder_enable_device(struct cpuidle_driver *drv, */ static void ladder_reflect(struct cpuidle_device *dev, int index) { - struct ladder_device *ldev = &__get_cpu_var(ladder_devices); + struct ladder_device *ldev = this_cpu_ptr(&ladder_devices); if (index > 0) ldev->last_state_idx = index; } diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 34db2fb3ef1e..710a233b9b0d 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -289,7 +289,7 @@ static void get_typical_interval(struct menu_device *data) */ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) { - struct menu_device *data = &__get_cpu_var(menu_devices); + struct menu_device *data = this_cpu_ptr(&menu_devices); int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); int i; unsigned int interactivity_req; @@ -372,7 +372,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) */ static void menu_reflect(struct cpuidle_device *dev, int index) { - struct menu_device *data = &__get_cpu_var(menu_devices); + struct menu_device *data = this_cpu_ptr(&menu_devices); data->last_state_idx = index; if (index >= 0) data->needs_update = 1; @@ -385,7 +385,7 @@ static void menu_reflect(struct cpuidle_device *dev, int index) */ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) { - struct menu_device *data = &__get_cpu_var(menu_devices); + struct menu_device *data = this_cpu_ptr(&menu_devices); int last_idx = data->last_state_idx; struct cpuidle_state *target = &drv->states[last_idx]; unsigned int measured_us; -- GitLab From 879d92745a1a5a6573dee83cfa2953413fed23fc Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:31 -0500 Subject: [PATCH 0649/5088] drivers/oprofile: Replace __get_cpu_var uses for address calculation Replace the uses of __get_cpu_var for address calculation with this_cpu_ptr. Cc: Robert Richter Cc: oprofile-list@lists.sf.net Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/oprofile/cpu_buffer.c | 10 +++++----- drivers/oprofile/timer_int.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 8aa73fac6ad4..0581461c3a67 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -45,7 +45,7 @@ unsigned long oprofile_get_cpu_buffer_size(void) void oprofile_cpu_buffer_inc_smpl_lost(void) { - struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer); + struct oprofile_cpu_buffer *cpu_buf = this_cpu_ptr(&op_cpu_buffer); cpu_buf->sample_lost_overflow++; } @@ -297,7 +297,7 @@ __oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, unsigned long event, int is_kernel, struct task_struct *task) { - struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer); + struct oprofile_cpu_buffer *cpu_buf = this_cpu_ptr(&op_cpu_buffer); unsigned long backtrace = oprofile_backtrace_depth; /* @@ -357,7 +357,7 @@ oprofile_write_reserve(struct op_entry *entry, struct pt_regs * const regs, { struct op_sample *sample; int is_kernel = !user_mode(regs); - struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer); + struct oprofile_cpu_buffer *cpu_buf = this_cpu_ptr(&op_cpu_buffer); cpu_buf->sample_received++; @@ -412,13 +412,13 @@ int oprofile_write_commit(struct op_entry *entry) void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) { - struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer); + struct oprofile_cpu_buffer *cpu_buf = this_cpu_ptr(&op_cpu_buffer); log_sample(cpu_buf, pc, 0, is_kernel, event, NULL); } void oprofile_add_trace(unsigned long pc) { - struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer); + struct oprofile_cpu_buffer *cpu_buf = this_cpu_ptr(&op_cpu_buffer); if (!cpu_buf->tracing) return; diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index 61be1d9c16c8..bdef916e5dda 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c @@ -32,7 +32,7 @@ static enum hrtimer_restart oprofile_hrtimer_notify(struct hrtimer *hrtimer) static void __oprofile_hrtimer_start(void *unused) { - struct hrtimer *hrtimer = &__get_cpu_var(oprofile_hrtimer); + struct hrtimer *hrtimer = this_cpu_ptr(&oprofile_hrtimer); if (!ctr_running) return; -- GitLab From 27d051677977da11dc50caeb210204b587c94eb5 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:32 -0500 Subject: [PATCH 0650/5088] drivers/clocksource: Replace __get_cpu_var used for address calculation Replace __get_cpu_var used for address calculation with this_cpu_ptr. Acked-by: James Hogan Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/clocksource/metag_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clocksource/metag_generic.c b/drivers/clocksource/metag_generic.c index 9e4db41abe3c..b7384b853e5a 100644 --- a/drivers/clocksource/metag_generic.c +++ b/drivers/clocksource/metag_generic.c @@ -90,7 +90,7 @@ static struct clocksource clocksource_metag = { static irqreturn_t metag_timer_interrupt(int irq, void *dummy) { - struct clock_event_device *evt = &__get_cpu_var(local_clockevent); + struct clock_event_device *evt = this_cpu_ptr(&local_clockevent); evt->event_handler(evt); -- GitLab From 70b2776a5cb16c39ff5451c4eee72691734eabfc Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:33 -0500 Subject: [PATCH 0651/5088] drivers/net/ethernet/tile: Replace __get_cpu_var uses for address calculation Replace with this_cpu_ptr. Acked-by: Chris Metcalf Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/net/ethernet/tile/tilegx.c | 18 +++++++++--------- drivers/net/ethernet/tile/tilepro.c | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 69557a26f749..e354742c3f59 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -423,7 +423,7 @@ static void tile_net_pop_all_buffers(int instance, int stack) /* Provide linux buffers to mPIPE. */ static void tile_net_provide_needed_buffers(void) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); int instance, kind; for (instance = 0; instance < NR_MPIPE_MAX && info->mpipe[instance].has_iqueue; instance++) { @@ -585,7 +585,7 @@ static void tile_net_receive_skb(struct net_device *dev, struct sk_buff *skb, /* Handle a packet. Return true if "processed", false if "filtered". */ static bool tile_net_handle_packet(int instance, gxio_mpipe_idesc_t *idesc) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); struct mpipe_data *md = &mpipe_data[instance]; struct net_device *dev = md->tile_net_devs_for_channel[idesc->channel]; uint8_t l2_offset; @@ -651,7 +651,7 @@ static bool tile_net_handle_packet(int instance, gxio_mpipe_idesc_t *idesc) */ static int tile_net_poll(struct napi_struct *napi, int budget) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); unsigned int work = 0; gxio_mpipe_idesc_t *idesc; int instance, i, n; @@ -700,7 +700,7 @@ static int tile_net_poll(struct napi_struct *napi, int budget) /* Handle an ingress interrupt from an instance on the current cpu. */ static irqreturn_t tile_net_handle_ingress_irq(int irq, void *id) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); napi_schedule(&info->mpipe[(uint64_t)id].napi); return IRQ_HANDLED; } @@ -763,7 +763,7 @@ static enum hrtimer_restart tile_net_handle_tx_wake_timer(struct hrtimer *t) /* Make sure the egress timer is scheduled. */ static void tile_net_schedule_egress_timer(void) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); if (!info->egress_timer_scheduled) { hrtimer_start(&info->egress_timer, @@ -780,7 +780,7 @@ static void tile_net_schedule_egress_timer(void) */ static enum hrtimer_restart tile_net_handle_egress_timer(struct hrtimer *t) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); unsigned long irqflags; bool pending = false; int i, instance; @@ -1996,7 +1996,7 @@ static unsigned int tile_net_tx_frags(struct frag *frags, /* Help the kernel transmit a packet. */ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); struct tile_net_priv *priv = netdev_priv(dev); int instance = priv->instance; struct mpipe_data *md = &mpipe_data[instance]; @@ -2138,7 +2138,7 @@ static int tile_net_set_mac_address(struct net_device *dev, void *p) static void tile_net_netpoll(struct net_device *dev) { int instance = mpipe_instance(dev); - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); struct mpipe_data *md = &mpipe_data[instance]; disable_percpu_irq(md->ingress_irq); @@ -2237,7 +2237,7 @@ static void tile_net_dev_init(const char *name, const uint8_t *mac) /* Per-cpu module initialization. */ static void tile_net_init_module_percpu(void *unused) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); int my_cpu = smp_processor_id(); int instance; diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c index 88c712126692..3faf03fce827 100644 --- a/drivers/net/ethernet/tile/tilepro.c +++ b/drivers/net/ethernet/tile/tilepro.c @@ -996,13 +996,13 @@ static void tile_net_register(void *dev_ptr) PDEBUG("tile_net_register(queue_id %d)\n", queue_id); if (!strcmp(dev->name, "xgbe0")) - info = &__get_cpu_var(hv_xgbe0); + info = this_cpu_ptr(&hv_xgbe0); else if (!strcmp(dev->name, "xgbe1")) - info = &__get_cpu_var(hv_xgbe1); + info = this_cpu_ptr(&hv_xgbe1); else if (!strcmp(dev->name, "gbe0")) - info = &__get_cpu_var(hv_gbe0); + info = this_cpu_ptr(&hv_gbe0); else if (!strcmp(dev->name, "gbe1")) - info = &__get_cpu_var(hv_gbe1); + info = this_cpu_ptr(&hv_gbe1); else BUG(); -- GitLab From f7f66b05aa2ac2632c5441a3f129f3be827fe7e7 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:34 -0500 Subject: [PATCH 0652/5088] watchdog: Replace __raw_get_cpu_var uses Most of these are the uses of &__raw_get_cpu_var for address calculation. touch_softlockup_watchdog_sync() uses __raw_get_cpu_var to write to per cpu variables. Use __this_cpu_write instead. Cc: Wim Van Sebroeck Cc: linux-watchdog@vger.kernel.org Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- kernel/watchdog.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index a8d6914030fe..dca8cae7e55d 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -185,7 +185,7 @@ void touch_nmi_watchdog(void) * case we shouldn't have to worry about the watchdog * going off. */ - __raw_get_cpu_var(watchdog_nmi_touch) = true; + raw_cpu_write(watchdog_nmi_touch, true); touch_softlockup_watchdog(); } EXPORT_SYMBOL(touch_nmi_watchdog); @@ -194,8 +194,8 @@ EXPORT_SYMBOL(touch_nmi_watchdog); void touch_softlockup_watchdog_sync(void) { - __raw_get_cpu_var(softlockup_touch_sync) = true; - __raw_get_cpu_var(watchdog_touch_ts) = 0; + __this_cpu_write(softlockup_touch_sync, true); + __this_cpu_write(watchdog_touch_ts, 0); } #ifdef CONFIG_HARDLOCKUP_DETECTOR @@ -387,7 +387,7 @@ static void watchdog_set_prio(unsigned int policy, unsigned int prio) static void watchdog_enable(unsigned int cpu) { - struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer); + struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer); /* kick off the timer for the hardlockup detector */ hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); @@ -407,7 +407,7 @@ static void watchdog_enable(unsigned int cpu) static void watchdog_disable(unsigned int cpu) { - struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer); + struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer); watchdog_set_prio(SCHED_NORMAL, 0); hrtimer_cancel(hrtimer); @@ -534,7 +534,7 @@ static struct smp_hotplug_thread watchdog_threads = { static void restart_watchdog_hrtimer(void *info) { - struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer); + struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer); int ret; /* -- GitLab From 903ceff7ca7b4d80c083a80ee5163b74e9fa359f Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:35 -0500 Subject: [PATCH 0653/5088] net: Replace get_cpu_var through this_cpu_ptr Replace uses of get_cpu_var for address calculation through this_cpu_ptr. Cc: netdev@vger.kernel.org Cc: Eric Dumazet Acked-by: David S. Miller Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- include/net/netfilter/nf_conntrack.h | 2 +- include/net/snmp.h | 6 +++--- net/core/dev.c | 14 +++++++------- net/core/drop_monitor.c | 2 +- net/core/skbuff.c | 2 +- net/ipv4/route.c | 4 ++-- net/ipv4/syncookies.c | 2 +- net/ipv4/tcp.c | 2 +- net/ipv4/tcp_output.c | 2 +- net/ipv6/syncookies.c | 2 +- net/rds/ib_rdma.c | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 37252f71a380..c8a7db605e03 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -242,7 +242,7 @@ extern s32 (*nf_ct_nat_offset)(const struct nf_conn *ct, DECLARE_PER_CPU(struct nf_conn, nf_conntrack_untracked); static inline struct nf_conn *nf_ct_untracked_get(void) { - return &__raw_get_cpu_var(nf_conntrack_untracked); + return raw_cpu_ptr(&nf_conntrack_untracked); } void nf_ct_untracked_status_or(unsigned long bits); diff --git a/include/net/snmp.h b/include/net/snmp.h index f1f27fdbb0d5..e154133877a2 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -168,7 +168,7 @@ struct linux_xfrm_mib { #define SNMP_ADD_STATS64_BH(mib, field, addend) \ do { \ - __typeof__(*mib) *ptr = __this_cpu_ptr(mib); \ + __typeof__(*mib) *ptr = raw_cpu_ptr(mib); \ u64_stats_update_begin(&ptr->syncp); \ ptr->mibs[field] += addend; \ u64_stats_update_end(&ptr->syncp); \ @@ -189,8 +189,8 @@ struct linux_xfrm_mib { #define SNMP_INC_STATS64(mib, field) SNMP_ADD_STATS64(mib, field, 1) #define SNMP_UPD_PO_STATS64_BH(mib, basefield, addend) \ do { \ - __typeof__(*mib) *ptr; \ - ptr = __this_cpu_ptr(mib); \ + __typeof__(*mib) *ptr; \ + ptr = raw_cpu_ptr((mib)); \ u64_stats_update_begin(&ptr->syncp); \ ptr->mibs[basefield##PKTS]++; \ ptr->mibs[basefield##OCTETS] += addend; \ diff --git a/net/core/dev.c b/net/core/dev.c index b65a5051361f..9ef13ff354fe 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2153,7 +2153,7 @@ static inline void __netif_reschedule(struct Qdisc *q) unsigned long flags; local_irq_save(flags); - sd = &__get_cpu_var(softnet_data); + sd = this_cpu_ptr(&softnet_data); q->next_sched = NULL; *sd->output_queue_tailp = q; sd->output_queue_tailp = &q->next_sched; @@ -3195,7 +3195,7 @@ static void rps_trigger_softirq(void *data) static int rps_ipi_queued(struct softnet_data *sd) { #ifdef CONFIG_RPS - struct softnet_data *mysd = &__get_cpu_var(softnet_data); + struct softnet_data *mysd = this_cpu_ptr(&softnet_data); if (sd != mysd) { sd->rps_ipi_next = mysd->rps_ipi_list; @@ -3222,7 +3222,7 @@ static bool skb_flow_limit(struct sk_buff *skb, unsigned int qlen) if (qlen < (netdev_max_backlog >> 1)) return false; - sd = &__get_cpu_var(softnet_data); + sd = this_cpu_ptr(&softnet_data); rcu_read_lock(); fl = rcu_dereference(sd->flow_limit); @@ -3369,7 +3369,7 @@ EXPORT_SYMBOL(netif_rx_ni); static void net_tx_action(struct softirq_action *h) { - struct softnet_data *sd = &__get_cpu_var(softnet_data); + struct softnet_data *sd = this_cpu_ptr(&softnet_data); if (sd->completion_queue) { struct sk_buff *clist; @@ -3794,7 +3794,7 @@ EXPORT_SYMBOL(netif_receive_skb); static void flush_backlog(void *arg) { struct net_device *dev = arg; - struct softnet_data *sd = &__get_cpu_var(softnet_data); + struct softnet_data *sd = this_cpu_ptr(&softnet_data); struct sk_buff *skb, *tmp; rps_lock(sd); @@ -4301,7 +4301,7 @@ void __napi_schedule(struct napi_struct *n) unsigned long flags; local_irq_save(flags); - ____napi_schedule(&__get_cpu_var(softnet_data), n); + ____napi_schedule(this_cpu_ptr(&softnet_data), n); local_irq_restore(flags); } EXPORT_SYMBOL(__napi_schedule); @@ -4422,7 +4422,7 @@ EXPORT_SYMBOL(netif_napi_del); static void net_rx_action(struct softirq_action *h) { - struct softnet_data *sd = &__get_cpu_var(softnet_data); + struct softnet_data *sd = this_cpu_ptr(&softnet_data); unsigned long time_limit = jiffies + 2; int budget = netdev_budget; void *have; diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 50f9a9db5792..252e155c837b 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -146,7 +146,7 @@ static void trace_drop_common(struct sk_buff *skb, void *location) unsigned long flags; local_irq_save(flags); - data = &__get_cpu_var(dm_cpu_data); + data = this_cpu_ptr(&dm_cpu_data); spin_lock(&data->lock); dskb = data->skb; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 163b673f9e62..adfc7ee1acf2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -345,7 +345,7 @@ static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) unsigned long flags; local_irq_save(flags); - nc = &__get_cpu_var(netdev_alloc_cache); + nc = this_cpu_ptr(&netdev_alloc_cache); if (unlikely(!nc->frag.page)) { refill: for (order = NETDEV_FRAG_PAGE_MAX_ORDER; ;) { diff --git a/net/ipv4/route.c b/net/ipv4/route.c index eaa4b000c7b4..7d6f4e021846 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1311,7 +1311,7 @@ static bool rt_cache_route(struct fib_nh *nh, struct rtable *rt) if (rt_is_input_route(rt)) { p = (struct rtable **)&nh->nh_rth_input; } else { - p = (struct rtable **)__this_cpu_ptr(nh->nh_pcpu_rth_output); + p = (struct rtable **)raw_cpu_ptr(nh->nh_pcpu_rth_output); } orig = *p; @@ -1939,7 +1939,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, do_cache = false; goto add; } - prth = __this_cpu_ptr(nh->nh_pcpu_rth_output); + prth = raw_cpu_ptr(nh->nh_pcpu_rth_output); } rth = rcu_dereference(*prth); if (rt_cache_valid(rth)) { diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index c0c75688896e..f83391bfdd76 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -40,7 +40,7 @@ static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, net_get_random_once(syncookie_secret, sizeof(syncookie_secret)); - tmp = __get_cpu_var(ipv4_cookie_scratch); + tmp = this_cpu_ptr(ipv4_cookie_scratch); memcpy(tmp + 4, syncookie_secret[c], sizeof(syncookie_secret[c])); tmp[0] = (__force u32)saddr; tmp[1] = (__force u32)daddr; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 541f26a67ba2..b2cab7770a11 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3058,7 +3058,7 @@ struct tcp_md5sig_pool *tcp_get_md5sig_pool(void) local_bh_disable(); p = ACCESS_ONCE(tcp_md5sig_pool); if (p) - return __this_cpu_ptr(p); + return raw_cpu_ptr(p); local_bh_enable(); return NULL; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 5a7c41fbc6d3..d145f7ef78f3 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -842,7 +842,7 @@ void tcp_wfree(struct sk_buff *skb) /* queue this socket to tasklet queue */ local_irq_save(flags); - tsq = &__get_cpu_var(tsq_tasklet); + tsq = this_cpu_ptr(&tsq_tasklet); list_add(&tp->tsq_node, &tsq->head); tasklet_schedule(&tsq->tasklet); local_irq_restore(flags); diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 83cea1d39466..637de5b87589 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -67,7 +67,7 @@ static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *dadd net_get_random_once(syncookie6_secret, sizeof(syncookie6_secret)); - tmp = __get_cpu_var(ipv6_cookie_scratch); + tmp = this_cpu_ptr(ipv6_cookie_scratch); /* * we have 320 bits of information to hash, copy in the remaining diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index e8fdb172adbb..273b8bff6ba4 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -267,7 +267,7 @@ static inline struct rds_ib_mr *rds_ib_reuse_fmr(struct rds_ib_mr_pool *pool) unsigned long *flag; preempt_disable(); - flag = &__get_cpu_var(clean_list_grace); + flag = this_cpu_ptr(&clean_list_grace); set_bit(CLEAN_LIST_BUSY_BIT, flag); ret = llist_del_first(&pool->clean_list); if (ret) -- GitLab From 1f125e76f5c134b0a904ef30e96ee8da6a49f4b4 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:36 -0500 Subject: [PATCH 0654/5088] md: Replace __this_cpu_ptr with raw_cpu_ptr __this_cpu_ptr is being phased out. Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/md/dm-stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c index 28a90122a5a8..87f86c77b094 100644 --- a/drivers/md/dm-stats.c +++ b/drivers/md/dm-stats.c @@ -548,7 +548,7 @@ void dm_stats_account_io(struct dm_stats *stats, unsigned long bi_rw, * A race condition can at worst result in the merged flag being * misrepresented, so we don't have to disable preemption here. */ - last = __this_cpu_ptr(stats->last); + last = raw_cpu_ptr(stats->last); stats_aux->merged = (bi_sector == (ACCESS_ONCE(last->last_sector) && ((bi_rw & (REQ_WRITE | REQ_DISCARD)) == -- GitLab From bd83e65bfaedafef1ba21ce19c1ea7913da01bec Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:37 -0500 Subject: [PATCH 0655/5088] metag: Replace __get_cpu_var uses for address calculation Replace __get_cpu_var uses for address calculation with this_cpu_ptr(). Acked-by: James Hogan Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/metag/kernel/perf/perf_event.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c index 02c08737f6aa..2478ec6d23c9 100644 --- a/arch/metag/kernel/perf/perf_event.c +++ b/arch/metag/kernel/perf/perf_event.c @@ -258,7 +258,7 @@ int metag_pmu_event_set_period(struct perf_event *event, static void metag_pmu_start(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; @@ -306,7 +306,7 @@ static void metag_pmu_stop(struct perf_event *event, int flags) static int metag_pmu_add(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; int idx = 0, ret = 0; @@ -348,7 +348,7 @@ static int metag_pmu_add(struct perf_event *event, int flags) static void metag_pmu_del(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; @@ -597,7 +597,7 @@ static int _hw_perf_event_init(struct perf_event *event) static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx) { - struct cpu_hw_events *events = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *events = this_cpu_ptr(&cpu_hw_events); unsigned int config = event->config; unsigned int tmp = config & 0xf0; unsigned long flags; @@ -670,7 +670,7 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx) static void metag_pmu_disable_counter(struct hw_perf_event *event, int idx) { - struct cpu_hw_events *events = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *events = this_cpu_ptr(&cpu_hw_events); unsigned int tmp = 0; unsigned long flags; @@ -718,7 +718,7 @@ static u64 metag_pmu_read_counter(int idx) static void metag_pmu_write_counter(int idx, u32 val) { - struct cpu_hw_events *events = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *events = this_cpu_ptr(&cpu_hw_events); u32 tmp = 0; unsigned long flags; @@ -751,7 +751,7 @@ static int metag_pmu_event_map(int idx) static irqreturn_t metag_pmu_counter_overflow(int irq, void *dev) { int idx = (int)dev; - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); struct perf_event *event = cpuhw->events[idx]; struct hw_perf_event *hwc = &event->hw; struct pt_regs *regs = get_irq_regs(); -- GitLab From eee8492db674a5c89daa83158d8bf2839efc8850 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:38 -0500 Subject: [PATCH 0656/5088] drivers/net/ethernet/tile: __get_cpu_var call introduced in 3.14 Another case was merged for 3.14-rc1 Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/net/ethernet/tile/tilegx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index e354742c3f59..049747f558c9 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -551,7 +551,7 @@ static inline bool filter_packet(struct net_device *dev, void *buf) static void tile_net_receive_skb(struct net_device *dev, struct sk_buff *skb, gxio_mpipe_idesc_t *idesc, unsigned long len) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); struct tile_net_priv *priv = netdev_priv(dev); int instance = priv->instance; @@ -1927,7 +1927,7 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue, */ static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev) { - struct tile_net_info *info = &__get_cpu_var(per_cpu_info); + struct tile_net_info *info = this_cpu_ptr(&per_cpu_info); struct tile_net_priv *priv = netdev_priv(dev); int channel = priv->echannel; int instance = priv->instance; -- GitLab From 532d0d0690d1532dcc5a190162ad820b636bcd4d Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:39 -0500 Subject: [PATCH 0657/5088] irqchips: Replace __this_cpu_ptr uses [ARM specific] These are generally replaced with raw_cpu_ptr. However, in gic_get_percpu_base() we immediately dereference the pointer. This is equivalent to a raw_cpu_read. So use that operation there. Cc: nicolas.pitre@linaro.org Cc: Russell King Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/irqchip/irq-gic.c | 10 +++++----- kernel/irq/chip.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 4b959e606fe8..399a707ec51e 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -102,7 +102,7 @@ static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly; #ifdef CONFIG_GIC_NON_BANKED static void __iomem *gic_get_percpu_base(union gic_base *base) { - return *__this_cpu_ptr(base->percpu_base); + return raw_cpu_read(base->percpu_base); } static void __iomem *gic_get_common_base(union gic_base *base) @@ -504,11 +504,11 @@ static void gic_cpu_save(unsigned int gic_nr) if (!dist_base || !cpu_base) return; - ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable); + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_enable); for (i = 0; i < DIV_ROUND_UP(32, 32); i++) ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4); - ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf); + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf); for (i = 0; i < DIV_ROUND_UP(32, 16); i++) ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4); @@ -530,11 +530,11 @@ static void gic_cpu_restore(unsigned int gic_nr) if (!dist_base || !cpu_base) return; - ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable); + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_enable); for (i = 0; i < DIV_ROUND_UP(32, 32); i++) writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4); - ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf); + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf); for (i = 0; i < DIV_ROUND_UP(32, 16); i++) writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index a2b28a2fd7b1..cca7292fc61e 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -669,7 +669,7 @@ void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct irqaction *action = desc->action; - void *dev_id = __this_cpu_ptr(action->percpu_dev_id); + void *dev_id = raw_cpu_ptr(action->percpu_dev_id); irqreturn_t res; kstat_incr_irqs_this_cpu(irq, desc); -- GitLab From 89cbc76768c2fa4ed95545bf961f3a14ddfeed21 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:40 -0500 Subject: [PATCH 0658/5088] x86: Replace __get_cpu_var uses __get_cpu_var() is used for multiple purposes in the kernel source. One of them is address calculation via the form &__get_cpu_var(x). This calculates the address for the instance of the percpu variable of the current processor based on an offset. Other use cases are for storing and retrieving data from the current processors percpu area. __get_cpu_var() can be used as an lvalue when writing data or on the right side of an assignment. __get_cpu_var() is defined as : #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) __get_cpu_var() always only does an address determination. However, store and retrieve operations could use a segment prefix (or global register on other platforms) to avoid the address calculation. this_cpu_write() and this_cpu_read() can directly take an offset into a percpu area and use optimized assembly code to read and write per cpu variables. This patch converts __get_cpu_var into either an explicit address calculation using this_cpu_ptr() or into a use of this_cpu operations that use the offset. Thereby address calculations are avoided and less registers are used when code is generated. Transformations done to __get_cpu_var() 1. Determine the address of the percpu instance of the current processor. DEFINE_PER_CPU(int, y); int *x = &__get_cpu_var(y); Converts to int *x = this_cpu_ptr(&y); 2. Same as #1 but this time an array structure is involved. DEFINE_PER_CPU(int, y[20]); int *x = __get_cpu_var(y); Converts to int *x = this_cpu_ptr(y); 3. Retrieve the content of the current processors instance of a per cpu variable. DEFINE_PER_CPU(int, y); int x = __get_cpu_var(y) Converts to int x = __this_cpu_read(y); 4. Retrieve the content of a percpu struct DEFINE_PER_CPU(struct mystruct, y); struct mystruct x = __get_cpu_var(y); Converts to memcpy(&x, this_cpu_ptr(&y), sizeof(x)); 5. Assignment to a per cpu variable DEFINE_PER_CPU(int, y) __get_cpu_var(y) = x; Converts to __this_cpu_write(y, x); 6. Increment/Decrement etc of a per cpu variable DEFINE_PER_CPU(int, y); __get_cpu_var(y)++ Converts to __this_cpu_inc(y) Cc: Thomas Gleixner Cc: x86@kernel.org Acked-by: H. Peter Anvin Acked-by: Ingo Molnar Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/x86/include/asm/debugreg.h | 4 +- arch/x86/include/asm/uv/uv_hub.h | 2 +- arch/x86/kernel/apb_timer.c | 4 +- arch/x86/kernel/apic/apic.c | 4 +- arch/x86/kernel/cpu/common.c | 6 +-- arch/x86/kernel/cpu/mcheck/mce-inject.c | 6 +-- arch/x86/kernel/cpu/mcheck/mce.c | 46 ++++++++++----------- arch/x86/kernel/cpu/mcheck/mce_amd.c | 2 +- arch/x86/kernel/cpu/mcheck/mce_intel.c | 22 +++++----- arch/x86/kernel/cpu/perf_event.c | 22 +++++----- arch/x86/kernel/cpu/perf_event_amd.c | 4 +- arch/x86/kernel/cpu/perf_event_intel.c | 18 ++++---- arch/x86/kernel/cpu/perf_event_intel_ds.c | 20 ++++----- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 12 +++--- arch/x86/kernel/cpu/perf_event_intel_rapl.c | 12 +++--- arch/x86/kernel/cpu/perf_event_knc.c | 2 +- arch/x86/kernel/cpu/perf_event_p4.c | 6 +-- arch/x86/kernel/hw_breakpoint.c | 8 ++-- arch/x86/kernel/irq_64.c | 6 +-- arch/x86/kernel/kvm.c | 22 +++++----- arch/x86/kvm/svm.c | 6 +-- arch/x86/kvm/vmx.c | 10 ++--- arch/x86/kvm/x86.c | 2 +- arch/x86/mm/kmemcheck/kmemcheck.c | 14 +++---- arch/x86/oprofile/nmi_int.c | 8 ++-- arch/x86/platform/uv/uv_time.c | 2 +- arch/x86/xen/enlighten.c | 4 +- arch/x86/xen/multicalls.c | 8 ++-- arch/x86/xen/spinlock.c | 2 +- arch/x86/xen/time.c | 10 ++--- 30 files changed, 147 insertions(+), 147 deletions(-) diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h index 4b528a970bd4..61fd18b83b6c 100644 --- a/arch/x86/include/asm/debugreg.h +++ b/arch/x86/include/asm/debugreg.h @@ -97,11 +97,11 @@ extern void hw_breakpoint_restore(void); DECLARE_PER_CPU(int, debug_stack_usage); static inline void debug_stack_usage_inc(void) { - __get_cpu_var(debug_stack_usage)++; + __this_cpu_inc(debug_stack_usage); } static inline void debug_stack_usage_dec(void) { - __get_cpu_var(debug_stack_usage)--; + __this_cpu_dec(debug_stack_usage); } int is_debug_stack(unsigned long addr); void debug_stack_set_zero(void); diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index c63e925fd6b7..bb84cfd5a1a1 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -164,7 +164,7 @@ struct uv_hub_info_s { }; DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); -#define uv_hub_info (&__get_cpu_var(__uv_hub_info)) +#define uv_hub_info this_cpu_ptr(&__uv_hub_info) #define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu)) /* diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index af5b08ab3b71..5972b108f15a 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c @@ -146,7 +146,7 @@ static inline int is_apbt_capable(void) static int __init apbt_clockevent_register(void) { struct sfi_timer_table_entry *mtmr; - struct apbt_dev *adev = &__get_cpu_var(cpu_apbt_dev); + struct apbt_dev *adev = this_cpu_ptr(&cpu_apbt_dev); mtmr = sfi_get_mtmr(APBT_CLOCKEVENT0_NUM); if (mtmr == NULL) { @@ -200,7 +200,7 @@ void apbt_setup_secondary_clock(void) if (!cpu) return; - adev = &__get_cpu_var(cpu_apbt_dev); + adev = this_cpu_ptr(&cpu_apbt_dev); if (!adev->timer) { adev->timer = dw_apb_clockevent_init(cpu, adev->name, APBT_CLOCKEVENT_RATING, adev_virt_addr(adev), diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 67760275544b..00853b254ab0 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -561,7 +561,7 @@ static DEFINE_PER_CPU(struct clock_event_device, lapic_events); */ static void setup_APIC_timer(void) { - struct clock_event_device *levt = &__get_cpu_var(lapic_events); + struct clock_event_device *levt = this_cpu_ptr(&lapic_events); if (this_cpu_has(X86_FEATURE_ARAT)) { lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP; @@ -696,7 +696,7 @@ calibrate_by_pmtimer(long deltapm, long *delta, long *deltatsc) static int __init calibrate_APIC_clock(void) { - struct clock_event_device *levt = &__get_cpu_var(lapic_events); + struct clock_event_device *levt = this_cpu_ptr(&lapic_events); void (*real_handler)(struct clock_event_device *dev); unsigned long deltaj; long delta, deltatsc; diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index e4ab2b42bd6f..5666eb9568fc 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1198,9 +1198,9 @@ DEFINE_PER_CPU(int, debug_stack_usage); int is_debug_stack(unsigned long addr) { - return __get_cpu_var(debug_stack_usage) || - (addr <= __get_cpu_var(debug_stack_addr) && - addr > (__get_cpu_var(debug_stack_addr) - DEBUG_STKSZ)); + return __this_cpu_read(debug_stack_usage) || + (addr <= __this_cpu_read(debug_stack_addr) && + addr > (__this_cpu_read(debug_stack_addr) - DEBUG_STKSZ)); } NOKPROBE_SYMBOL(is_debug_stack); diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c index 5ac2d1fb28bc..4cfba4371a71 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-inject.c +++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c @@ -83,7 +83,7 @@ static DEFINE_MUTEX(mce_inject_mutex); static int mce_raise_notify(unsigned int cmd, struct pt_regs *regs) { int cpu = smp_processor_id(); - struct mce *m = &__get_cpu_var(injectm); + struct mce *m = this_cpu_ptr(&injectm); if (!cpumask_test_cpu(cpu, mce_inject_cpumask)) return NMI_DONE; cpumask_clear_cpu(cpu, mce_inject_cpumask); @@ -97,7 +97,7 @@ static int mce_raise_notify(unsigned int cmd, struct pt_regs *regs) static void mce_irq_ipi(void *info) { int cpu = smp_processor_id(); - struct mce *m = &__get_cpu_var(injectm); + struct mce *m = this_cpu_ptr(&injectm); if (cpumask_test_cpu(cpu, mce_inject_cpumask) && m->inject_flags & MCJ_EXCEPTION) { @@ -109,7 +109,7 @@ static void mce_irq_ipi(void *info) /* Inject mce on current CPU */ static int raise_local(void) { - struct mce *m = &__get_cpu_var(injectm); + struct mce *m = this_cpu_ptr(&injectm); int context = MCJ_CTX(m->inject_flags); int ret = 0; int cpu = m->extcpu; diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index bd9ccda8087f..61a9668cebfd 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -400,7 +400,7 @@ static u64 mce_rdmsrl(u32 msr) if (offset < 0) return 0; - return *(u64 *)((char *)&__get_cpu_var(injectm) + offset); + return *(u64 *)((char *)this_cpu_ptr(&injectm) + offset); } if (rdmsrl_safe(msr, &v)) { @@ -422,7 +422,7 @@ static void mce_wrmsrl(u32 msr, u64 v) int offset = msr_to_offset(msr); if (offset >= 0) - *(u64 *)((char *)&__get_cpu_var(injectm) + offset) = v; + *(u64 *)((char *)this_cpu_ptr(&injectm) + offset) = v; return; } wrmsrl(msr, v); @@ -478,7 +478,7 @@ static DEFINE_PER_CPU(struct mce_ring, mce_ring); /* Runs with CPU affinity in workqueue */ static int mce_ring_empty(void) { - struct mce_ring *r = &__get_cpu_var(mce_ring); + struct mce_ring *r = this_cpu_ptr(&mce_ring); return r->start == r->end; } @@ -490,7 +490,7 @@ static int mce_ring_get(unsigned long *pfn) *pfn = 0; get_cpu(); - r = &__get_cpu_var(mce_ring); + r = this_cpu_ptr(&mce_ring); if (r->start == r->end) goto out; *pfn = r->ring[r->start]; @@ -504,7 +504,7 @@ static int mce_ring_get(unsigned long *pfn) /* Always runs in MCE context with preempt off */ static int mce_ring_add(unsigned long pfn) { - struct mce_ring *r = &__get_cpu_var(mce_ring); + struct mce_ring *r = this_cpu_ptr(&mce_ring); unsigned next; next = (r->end + 1) % MCE_RING_SIZE; @@ -526,7 +526,7 @@ int mce_available(struct cpuinfo_x86 *c) static void mce_schedule_work(void) { if (!mce_ring_empty()) - schedule_work(&__get_cpu_var(mce_work)); + schedule_work(this_cpu_ptr(&mce_work)); } DEFINE_PER_CPU(struct irq_work, mce_irq_work); @@ -551,7 +551,7 @@ static void mce_report_event(struct pt_regs *regs) return; } - irq_work_queue(&__get_cpu_var(mce_irq_work)); + irq_work_queue(this_cpu_ptr(&mce_irq_work)); } /* @@ -1045,7 +1045,7 @@ void do_machine_check(struct pt_regs *regs, long error_code) mce_gather_info(&m, regs); - final = &__get_cpu_var(mces_seen); + final = this_cpu_ptr(&mces_seen); *final = m; memset(valid_banks, 0, sizeof(valid_banks)); @@ -1278,22 +1278,22 @@ static unsigned long (*mce_adjust_timer)(unsigned long interval) = static int cmc_error_seen(void) { - unsigned long *v = &__get_cpu_var(mce_polled_error); + unsigned long *v = this_cpu_ptr(&mce_polled_error); return test_and_clear_bit(0, v); } static void mce_timer_fn(unsigned long data) { - struct timer_list *t = &__get_cpu_var(mce_timer); + struct timer_list *t = this_cpu_ptr(&mce_timer); unsigned long iv; int notify; WARN_ON(smp_processor_id() != data); - if (mce_available(__this_cpu_ptr(&cpu_info))) { + if (mce_available(this_cpu_ptr(&cpu_info))) { machine_check_poll(MCP_TIMESTAMP, - &__get_cpu_var(mce_poll_banks)); + this_cpu_ptr(&mce_poll_banks)); mce_intel_cmci_poll(); } @@ -1323,7 +1323,7 @@ static void mce_timer_fn(unsigned long data) */ void mce_timer_kick(unsigned long interval) { - struct timer_list *t = &__get_cpu_var(mce_timer); + struct timer_list *t = this_cpu_ptr(&mce_timer); unsigned long when = jiffies + interval; unsigned long iv = __this_cpu_read(mce_next_interval); @@ -1659,7 +1659,7 @@ static void mce_start_timer(unsigned int cpu, struct timer_list *t) static void __mcheck_cpu_init_timer(void) { - struct timer_list *t = &__get_cpu_var(mce_timer); + struct timer_list *t = this_cpu_ptr(&mce_timer); unsigned int cpu = smp_processor_id(); setup_timer(t, mce_timer_fn, cpu); @@ -1702,8 +1702,8 @@ void mcheck_cpu_init(struct cpuinfo_x86 *c) __mcheck_cpu_init_generic(); __mcheck_cpu_init_vendor(c); __mcheck_cpu_init_timer(); - INIT_WORK(&__get_cpu_var(mce_work), mce_process_work); - init_irq_work(&__get_cpu_var(mce_irq_work), &mce_irq_work_cb); + INIT_WORK(this_cpu_ptr(&mce_work), mce_process_work); + init_irq_work(this_cpu_ptr(&mce_irq_work), &mce_irq_work_cb); } /* @@ -1955,7 +1955,7 @@ static struct miscdevice mce_chrdev_device = { static void __mce_disable_bank(void *arg) { int bank = *((int *)arg); - __clear_bit(bank, __get_cpu_var(mce_poll_banks)); + __clear_bit(bank, this_cpu_ptr(mce_poll_banks)); cmci_disable_bank(bank); } @@ -2065,7 +2065,7 @@ static void mce_syscore_shutdown(void) static void mce_syscore_resume(void) { __mcheck_cpu_init_generic(); - __mcheck_cpu_init_vendor(__this_cpu_ptr(&cpu_info)); + __mcheck_cpu_init_vendor(raw_cpu_ptr(&cpu_info)); } static struct syscore_ops mce_syscore_ops = { @@ -2080,7 +2080,7 @@ static struct syscore_ops mce_syscore_ops = { static void mce_cpu_restart(void *data) { - if (!mce_available(__this_cpu_ptr(&cpu_info))) + if (!mce_available(raw_cpu_ptr(&cpu_info))) return; __mcheck_cpu_init_generic(); __mcheck_cpu_init_timer(); @@ -2096,14 +2096,14 @@ static void mce_restart(void) /* Toggle features for corrected errors */ static void mce_disable_cmci(void *data) { - if (!mce_available(__this_cpu_ptr(&cpu_info))) + if (!mce_available(raw_cpu_ptr(&cpu_info))) return; cmci_clear(); } static void mce_enable_ce(void *all) { - if (!mce_available(__this_cpu_ptr(&cpu_info))) + if (!mce_available(raw_cpu_ptr(&cpu_info))) return; cmci_reenable(); cmci_recheck(); @@ -2336,7 +2336,7 @@ static void mce_disable_cpu(void *h) unsigned long action = *(unsigned long *)h; int i; - if (!mce_available(__this_cpu_ptr(&cpu_info))) + if (!mce_available(raw_cpu_ptr(&cpu_info))) return; if (!(action & CPU_TASKS_FROZEN)) @@ -2354,7 +2354,7 @@ static void mce_reenable_cpu(void *h) unsigned long action = *(unsigned long *)h; int i; - if (!mce_available(__this_cpu_ptr(&cpu_info))) + if (!mce_available(raw_cpu_ptr(&cpu_info))) return; if (!(action & CPU_TASKS_FROZEN)) diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 1e49f8f41276..5d4999f95aec 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -310,7 +310,7 @@ static void amd_threshold_interrupt(void) * event. */ machine_check_poll(MCP_TIMESTAMP, - &__get_cpu_var(mce_poll_banks)); + this_cpu_ptr(&mce_poll_banks)); if (high & MASK_OVERFLOW_HI) { rdmsrl(address, m.misc); diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c index 3bdb95ae8c43..b3c97bafc123 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_intel.c +++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c @@ -86,7 +86,7 @@ void mce_intel_cmci_poll(void) { if (__this_cpu_read(cmci_storm_state) == CMCI_STORM_NONE) return; - machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned)); + machine_check_poll(MCP_TIMESTAMP, this_cpu_ptr(&mce_banks_owned)); } void mce_intel_hcpu_update(unsigned long cpu) @@ -145,7 +145,7 @@ static void cmci_storm_disable_banks(void) u64 val; raw_spin_lock_irqsave(&cmci_discover_lock, flags); - owned = __get_cpu_var(mce_banks_owned); + owned = this_cpu_ptr(mce_banks_owned); for_each_set_bit(bank, owned, MAX_NR_BANKS) { rdmsrl(MSR_IA32_MCx_CTL2(bank), val); val &= ~MCI_CTL2_CMCI_EN; @@ -195,7 +195,7 @@ static void intel_threshold_interrupt(void) { if (cmci_storm_detect()) return; - machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned)); + machine_check_poll(MCP_TIMESTAMP, this_cpu_ptr(&mce_banks_owned)); mce_notify_irq(); } @@ -206,7 +206,7 @@ static void intel_threshold_interrupt(void) */ static void cmci_discover(int banks) { - unsigned long *owned = (void *)&__get_cpu_var(mce_banks_owned); + unsigned long *owned = (void *)this_cpu_ptr(&mce_banks_owned); unsigned long flags; int i; int bios_wrong_thresh = 0; @@ -228,7 +228,7 @@ static void cmci_discover(int banks) /* Already owned by someone else? */ if (val & MCI_CTL2_CMCI_EN) { clear_bit(i, owned); - __clear_bit(i, __get_cpu_var(mce_poll_banks)); + __clear_bit(i, this_cpu_ptr(mce_poll_banks)); continue; } @@ -252,7 +252,7 @@ static void cmci_discover(int banks) /* Did the enable bit stick? -- the bank supports CMCI */ if (val & MCI_CTL2_CMCI_EN) { set_bit(i, owned); - __clear_bit(i, __get_cpu_var(mce_poll_banks)); + __clear_bit(i, this_cpu_ptr(mce_poll_banks)); /* * We are able to set thresholds for some banks that * had a threshold of 0. This means the BIOS has not @@ -263,7 +263,7 @@ static void cmci_discover(int banks) (val & MCI_CTL2_CMCI_THRESHOLD_MASK)) bios_wrong_thresh = 1; } else { - WARN_ON(!test_bit(i, __get_cpu_var(mce_poll_banks))); + WARN_ON(!test_bit(i, this_cpu_ptr(mce_poll_banks))); } } raw_spin_unlock_irqrestore(&cmci_discover_lock, flags); @@ -284,10 +284,10 @@ void cmci_recheck(void) unsigned long flags; int banks; - if (!mce_available(__this_cpu_ptr(&cpu_info)) || !cmci_supported(&banks)) + if (!mce_available(raw_cpu_ptr(&cpu_info)) || !cmci_supported(&banks)) return; local_irq_save(flags); - machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned)); + machine_check_poll(MCP_TIMESTAMP, this_cpu_ptr(&mce_banks_owned)); local_irq_restore(flags); } @@ -296,12 +296,12 @@ static void __cmci_disable_bank(int bank) { u64 val; - if (!test_bit(bank, __get_cpu_var(mce_banks_owned))) + if (!test_bit(bank, this_cpu_ptr(mce_banks_owned))) return; rdmsrl(MSR_IA32_MCx_CTL2(bank), val); val &= ~MCI_CTL2_CMCI_EN; wrmsrl(MSR_IA32_MCx_CTL2(bank), val); - __clear_bit(bank, __get_cpu_var(mce_banks_owned)); + __clear_bit(bank, this_cpu_ptr(mce_banks_owned)); } /* diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 2879ecdaac43..5cd2b7967370 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -487,7 +487,7 @@ static int __x86_pmu_event_init(struct perf_event *event) void x86_pmu_disable_all(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int idx; for (idx = 0; idx < x86_pmu.num_counters; idx++) { @@ -505,7 +505,7 @@ void x86_pmu_disable_all(void) static void x86_pmu_disable(struct pmu *pmu) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (!x86_pmu_initialized()) return; @@ -522,7 +522,7 @@ static void x86_pmu_disable(struct pmu *pmu) void x86_pmu_enable_all(int added) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int idx; for (idx = 0; idx < x86_pmu.num_counters; idx++) { @@ -869,7 +869,7 @@ static void x86_pmu_start(struct perf_event *event, int flags); static void x86_pmu_enable(struct pmu *pmu) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct perf_event *event; struct hw_perf_event *hwc; int i, added = cpuc->n_added; @@ -1020,7 +1020,7 @@ void x86_pmu_enable_event(struct perf_event *event) */ static int x86_pmu_add(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc; int assign[X86_PMC_IDX_MAX]; int n, n0, ret; @@ -1071,7 +1071,7 @@ static int x86_pmu_add(struct perf_event *event, int flags) static void x86_pmu_start(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int idx = event->hw.idx; if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) @@ -1150,7 +1150,7 @@ void perf_event_print_debug(void) void x86_pmu_stop(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; if (__test_and_clear_bit(hwc->idx, cpuc->active_mask)) { @@ -1172,7 +1172,7 @@ void x86_pmu_stop(struct perf_event *event, int flags) static void x86_pmu_del(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int i; /* @@ -1227,7 +1227,7 @@ int x86_pmu_handle_irq(struct pt_regs *regs) int idx, handled = 0; u64 val; - cpuc = &__get_cpu_var(cpu_hw_events); + cpuc = this_cpu_ptr(&cpu_hw_events); /* * Some chipsets need to unmask the LVTPC in a particular spot @@ -1636,7 +1636,7 @@ static void x86_pmu_cancel_txn(struct pmu *pmu) */ static int x86_pmu_commit_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int assign[X86_PMC_IDX_MAX]; int n, ret; @@ -1995,7 +1995,7 @@ static unsigned long get_segment_base(unsigned int segment) if (idx > GDT_ENTRIES) return 0; - desc = __this_cpu_ptr(&gdt_page.gdt[0]); + desc = raw_cpu_ptr(gdt_page.gdt); } return get_desc_base(desc + idx); diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index beeb7cc07044..28926311aac1 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c @@ -699,7 +699,7 @@ __init int amd_pmu_init(void) void amd_pmu_enable_virt(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); cpuc->perf_ctr_virt_mask = 0; @@ -711,7 +711,7 @@ EXPORT_SYMBOL_GPL(amd_pmu_enable_virt); void amd_pmu_disable_virt(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); /* * We only mask out the Host-only bit so that host-only counting works diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 2502d0d9d246..6f80accf137d 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1045,7 +1045,7 @@ static inline bool intel_pmu_needs_lbr_smpl(struct perf_event *event) static void intel_pmu_disable_all(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); @@ -1058,7 +1058,7 @@ static void intel_pmu_disable_all(void) static void intel_pmu_enable_all(int added) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); intel_pmu_pebs_enable_all(); intel_pmu_lbr_enable_all(); @@ -1092,7 +1092,7 @@ static void intel_pmu_enable_all(int added) */ static void intel_pmu_nhm_workaround(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); static const unsigned long nhm_magic[4] = { 0x4300B5, 0x4300D2, @@ -1191,7 +1191,7 @@ static inline bool event_is_checkpointed(struct perf_event *event) static void intel_pmu_disable_event(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (unlikely(hwc->idx == INTEL_PMC_IDX_FIXED_BTS)) { intel_pmu_disable_bts(); @@ -1255,7 +1255,7 @@ static void intel_pmu_enable_fixed(struct hw_perf_event *hwc) static void intel_pmu_enable_event(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (unlikely(hwc->idx == INTEL_PMC_IDX_FIXED_BTS)) { if (!__this_cpu_read(cpu_hw_events.enabled)) @@ -1349,7 +1349,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) u64 status; int handled; - cpuc = &__get_cpu_var(cpu_hw_events); + cpuc = this_cpu_ptr(&cpu_hw_events); /* * No known reason to not always do late ACK, @@ -1781,7 +1781,7 @@ EXPORT_SYMBOL_GPL(perf_guest_get_msrs); static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct perf_guest_switch_msr *arr = cpuc->guest_switch_msrs; arr[0].msr = MSR_CORE_PERF_GLOBAL_CTRL; @@ -1802,7 +1802,7 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr) static struct perf_guest_switch_msr *core_guest_get_msrs(int *nr) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct perf_guest_switch_msr *arr = cpuc->guest_switch_msrs; int idx; @@ -1836,7 +1836,7 @@ static void core_pmu_enable_event(struct perf_event *event) static void core_pmu_enable_all(int added) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int idx; for (idx = 0; idx < x86_pmu.num_counters; idx++) { diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 696ade311ded..7b786b369789 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -475,7 +475,7 @@ void intel_pmu_enable_bts(u64 config) void intel_pmu_disable_bts(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); unsigned long debugctlmsr; if (!cpuc->ds) @@ -492,7 +492,7 @@ void intel_pmu_disable_bts(void) int intel_pmu_drain_bts_buffer(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct debug_store *ds = cpuc->ds; struct bts_record { u64 from; @@ -712,7 +712,7 @@ struct event_constraint *intel_pebs_constraints(struct perf_event *event) void intel_pmu_pebs_enable(struct perf_event *event) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT; @@ -727,7 +727,7 @@ void intel_pmu_pebs_enable(struct perf_event *event) void intel_pmu_pebs_disable(struct perf_event *event) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; cpuc->pebs_enabled &= ~(1ULL << hwc->idx); @@ -745,7 +745,7 @@ void intel_pmu_pebs_disable(struct perf_event *event) void intel_pmu_pebs_enable_all(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (cpuc->pebs_enabled) wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); @@ -753,7 +753,7 @@ void intel_pmu_pebs_enable_all(void) void intel_pmu_pebs_disable_all(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (cpuc->pebs_enabled) wrmsrl(MSR_IA32_PEBS_ENABLE, 0); @@ -761,7 +761,7 @@ void intel_pmu_pebs_disable_all(void) static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); unsigned long from = cpuc->lbr_entries[0].from; unsigned long old_to, to = cpuc->lbr_entries[0].to; unsigned long ip = regs->ip; @@ -868,7 +868,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event, * We cast to the biggest pebs_record but are careful not to * unconditionally access the 'extra' entries. */ - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct pebs_record_hsw *pebs = __pebs; struct perf_sample_data data; struct pt_regs regs; @@ -957,7 +957,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event, static void intel_pmu_drain_pebs_core(struct pt_regs *iregs) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct debug_store *ds = cpuc->ds; struct perf_event *event = cpuc->events[0]; /* PMC0 only */ struct pebs_record_core *at, *top; @@ -998,7 +998,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs) static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct debug_store *ds = cpuc->ds; struct perf_event *event = NULL; void *at, *top; diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index 9dd2459a4c73..ebb0d3144551 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c @@ -133,7 +133,7 @@ static void intel_pmu_lbr_filter(struct cpu_hw_events *cpuc); static void __intel_pmu_lbr_enable(void) { u64 debugctl; - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (cpuc->lbr_sel) wrmsrl(MSR_LBR_SELECT, cpuc->lbr_sel->config); @@ -183,7 +183,7 @@ void intel_pmu_lbr_reset(void) void intel_pmu_lbr_enable(struct perf_event *event) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (!x86_pmu.lbr_nr) return; @@ -203,7 +203,7 @@ void intel_pmu_lbr_enable(struct perf_event *event) void intel_pmu_lbr_disable(struct perf_event *event) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (!x86_pmu.lbr_nr) return; @@ -220,7 +220,7 @@ void intel_pmu_lbr_disable(struct perf_event *event) void intel_pmu_lbr_enable_all(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (cpuc->lbr_users) __intel_pmu_lbr_enable(); @@ -228,7 +228,7 @@ void intel_pmu_lbr_enable_all(void) void intel_pmu_lbr_disable_all(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (cpuc->lbr_users) __intel_pmu_lbr_disable(); @@ -332,7 +332,7 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) void intel_pmu_lbr_read(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (!cpuc->lbr_users) return; diff --git a/arch/x86/kernel/cpu/perf_event_intel_rapl.c b/arch/x86/kernel/cpu/perf_event_intel_rapl.c index 619f7699487a..d64f275fe274 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c +++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c @@ -135,7 +135,7 @@ static inline u64 rapl_scale(u64 v) * or use ldexp(count, -32). * Watts = Joules/Time delta */ - return v << (32 - __get_cpu_var(rapl_pmu)->hw_unit); + return v << (32 - __this_cpu_read(rapl_pmu->hw_unit)); } static u64 rapl_event_update(struct perf_event *event) @@ -187,7 +187,7 @@ static void rapl_stop_hrtimer(struct rapl_pmu *pmu) static enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer) { - struct rapl_pmu *pmu = __get_cpu_var(rapl_pmu); + struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); struct perf_event *event; unsigned long flags; @@ -234,7 +234,7 @@ static void __rapl_pmu_event_start(struct rapl_pmu *pmu, static void rapl_pmu_event_start(struct perf_event *event, int mode) { - struct rapl_pmu *pmu = __get_cpu_var(rapl_pmu); + struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); unsigned long flags; spin_lock_irqsave(&pmu->lock, flags); @@ -244,7 +244,7 @@ static void rapl_pmu_event_start(struct perf_event *event, int mode) static void rapl_pmu_event_stop(struct perf_event *event, int mode) { - struct rapl_pmu *pmu = __get_cpu_var(rapl_pmu); + struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); struct hw_perf_event *hwc = &event->hw; unsigned long flags; @@ -278,7 +278,7 @@ static void rapl_pmu_event_stop(struct perf_event *event, int mode) static int rapl_pmu_event_add(struct perf_event *event, int mode) { - struct rapl_pmu *pmu = __get_cpu_var(rapl_pmu); + struct rapl_pmu *pmu = __this_cpu_read(rapl_pmu); struct hw_perf_event *hwc = &event->hw; unsigned long flags; @@ -696,7 +696,7 @@ static int __init rapl_pmu_init(void) return -1; } - pmu = __get_cpu_var(rapl_pmu); + pmu = __this_cpu_read(rapl_pmu); pr_info("RAPL PMU detected, hw unit 2^-%d Joules," " API unit is 2^-32 Joules," diff --git a/arch/x86/kernel/cpu/perf_event_knc.c b/arch/x86/kernel/cpu/perf_event_knc.c index 838fa8772c62..5b0c232d1ee6 100644 --- a/arch/x86/kernel/cpu/perf_event_knc.c +++ b/arch/x86/kernel/cpu/perf_event_knc.c @@ -217,7 +217,7 @@ static int knc_pmu_handle_irq(struct pt_regs *regs) int bit, loops; u64 status; - cpuc = &__get_cpu_var(cpu_hw_events); + cpuc = this_cpu_ptr(&cpu_hw_events); knc_pmu_disable_all(); diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index 5d466b7d8609..f2e56783af3d 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c @@ -915,7 +915,7 @@ static inline void p4_pmu_disable_event(struct perf_event *event) static void p4_pmu_disable_all(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int idx; for (idx = 0; idx < x86_pmu.num_counters; idx++) { @@ -984,7 +984,7 @@ static void p4_pmu_enable_event(struct perf_event *event) static void p4_pmu_enable_all(int added) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int idx; for (idx = 0; idx < x86_pmu.num_counters; idx++) { @@ -1004,7 +1004,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) int idx, handled = 0; u64 val; - cpuc = &__get_cpu_var(cpu_hw_events); + cpuc = this_cpu_ptr(&cpu_hw_events); for (idx = 0; idx < x86_pmu.num_counters; idx++) { int overflow; diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index 5f9cf20cdb68..3d5fb509bdeb 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c @@ -108,7 +108,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp) int i; for (i = 0; i < HBP_NUM; i++) { - struct perf_event **slot = &__get_cpu_var(bp_per_reg[i]); + struct perf_event **slot = this_cpu_ptr(&bp_per_reg[i]); if (!*slot) { *slot = bp; @@ -122,7 +122,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp) set_debugreg(info->address, i); __this_cpu_write(cpu_debugreg[i], info->address); - dr7 = &__get_cpu_var(cpu_dr7); + dr7 = this_cpu_ptr(&cpu_dr7); *dr7 |= encode_dr7(i, info->len, info->type); set_debugreg(*dr7, 7); @@ -146,7 +146,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) int i; for (i = 0; i < HBP_NUM; i++) { - struct perf_event **slot = &__get_cpu_var(bp_per_reg[i]); + struct perf_event **slot = this_cpu_ptr(&bp_per_reg[i]); if (*slot == bp) { *slot = NULL; @@ -157,7 +157,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) if (WARN_ONCE(i == HBP_NUM, "Can't find any breakpoint slot")) return; - dr7 = &__get_cpu_var(cpu_dr7); + dr7 = this_cpu_ptr(&cpu_dr7); *dr7 &= ~__encode_dr7(i, info->len, info->type); set_debugreg(*dr7, 7); diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index 4d1c746892eb..e4b503d5558c 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c @@ -52,13 +52,13 @@ static inline void stack_overflow_check(struct pt_regs *regs) regs->sp <= curbase + THREAD_SIZE) return; - irq_stack_top = (u64)__get_cpu_var(irq_stack_union.irq_stack) + + irq_stack_top = (u64)this_cpu_ptr(irq_stack_union.irq_stack) + STACK_TOP_MARGIN; - irq_stack_bottom = (u64)__get_cpu_var(irq_stack_ptr); + irq_stack_bottom = (u64)__this_cpu_read(irq_stack_ptr); if (regs->sp >= irq_stack_top && regs->sp <= irq_stack_bottom) return; - oist = &__get_cpu_var(orig_ist); + oist = this_cpu_ptr(&orig_ist); estack_top = (u64)oist->ist[0] - EXCEPTION_STKSZ + STACK_TOP_MARGIN; estack_bottom = (u64)oist->ist[N_EXCEPTION_STACKS - 1]; if (regs->sp >= estack_top && regs->sp <= estack_bottom) diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 3dd8e2c4d74a..2b68102dbbeb 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -243,9 +243,9 @@ u32 kvm_read_and_reset_pf_reason(void) { u32 reason = 0; - if (__get_cpu_var(apf_reason).enabled) { - reason = __get_cpu_var(apf_reason).reason; - __get_cpu_var(apf_reason).reason = 0; + if (__this_cpu_read(apf_reason.enabled)) { + reason = __this_cpu_read(apf_reason.reason); + __this_cpu_write(apf_reason.reason, 0); } return reason; @@ -318,7 +318,7 @@ static void kvm_guest_apic_eoi_write(u32 reg, u32 val) * there's no need for lock or memory barriers. * An optimization barrier is implied in apic write. */ - if (__test_and_clear_bit(KVM_PV_EOI_BIT, &__get_cpu_var(kvm_apic_eoi))) + if (__test_and_clear_bit(KVM_PV_EOI_BIT, this_cpu_ptr(&kvm_apic_eoi))) return; apic_write(APIC_EOI, APIC_EOI_ACK); } @@ -329,13 +329,13 @@ void kvm_guest_cpu_init(void) return; if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF) && kvmapf) { - u64 pa = slow_virt_to_phys(&__get_cpu_var(apf_reason)); + u64 pa = slow_virt_to_phys(this_cpu_ptr(&apf_reason)); #ifdef CONFIG_PREEMPT pa |= KVM_ASYNC_PF_SEND_ALWAYS; #endif wrmsrl(MSR_KVM_ASYNC_PF_EN, pa | KVM_ASYNC_PF_ENABLED); - __get_cpu_var(apf_reason).enabled = 1; + __this_cpu_write(apf_reason.enabled, 1); printk(KERN_INFO"KVM setup async PF for cpu %d\n", smp_processor_id()); } @@ -344,8 +344,8 @@ void kvm_guest_cpu_init(void) unsigned long pa; /* Size alignment is implied but just to make it explicit. */ BUILD_BUG_ON(__alignof__(kvm_apic_eoi) < 4); - __get_cpu_var(kvm_apic_eoi) = 0; - pa = slow_virt_to_phys(&__get_cpu_var(kvm_apic_eoi)) + __this_cpu_write(kvm_apic_eoi, 0); + pa = slow_virt_to_phys(this_cpu_ptr(&kvm_apic_eoi)) | KVM_MSR_ENABLED; wrmsrl(MSR_KVM_PV_EOI_EN, pa); } @@ -356,11 +356,11 @@ void kvm_guest_cpu_init(void) static void kvm_pv_disable_apf(void) { - if (!__get_cpu_var(apf_reason).enabled) + if (!__this_cpu_read(apf_reason.enabled)) return; wrmsrl(MSR_KVM_ASYNC_PF_EN, 0); - __get_cpu_var(apf_reason).enabled = 0; + __this_cpu_write(apf_reason.enabled, 0); printk(KERN_INFO"Unregister pv shared memory for cpu %d\n", smp_processor_id()); @@ -716,7 +716,7 @@ __visible void kvm_lock_spinning(struct arch_spinlock *lock, __ticket_t want) if (in_nmi()) return; - w = &__get_cpu_var(klock_waiting); + w = this_cpu_ptr(&klock_waiting); cpu = smp_processor_id(); start = spin_time_start(); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index ddf742768ecf..1b0e90658d8d 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -670,7 +670,7 @@ static int svm_hardware_enable(void *garbage) if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) { wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT); - __get_cpu_var(current_tsc_ratio) = TSC_RATIO_DEFAULT; + __this_cpu_write(current_tsc_ratio, TSC_RATIO_DEFAULT); } @@ -1312,8 +1312,8 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); if (static_cpu_has(X86_FEATURE_TSCRATEMSR) && - svm->tsc_ratio != __get_cpu_var(current_tsc_ratio)) { - __get_cpu_var(current_tsc_ratio) = svm->tsc_ratio; + svm->tsc_ratio != __this_cpu_read(current_tsc_ratio)) { + __this_cpu_write(current_tsc_ratio, svm->tsc_ratio); wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_ratio); } } diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index bfe11cf124a1..36cf28a910b8 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1601,7 +1601,7 @@ static void reload_tss(void) /* * VT restores TR but not its size. Useless. */ - struct desc_ptr *gdt = &__get_cpu_var(host_gdt); + struct desc_ptr *gdt = this_cpu_ptr(&host_gdt); struct desc_struct *descs; descs = (void *)gdt->address; @@ -1647,7 +1647,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) static unsigned long segment_base(u16 selector) { - struct desc_ptr *gdt = &__get_cpu_var(host_gdt); + struct desc_ptr *gdt = this_cpu_ptr(&host_gdt); struct desc_struct *d; unsigned long table_base; unsigned long v; @@ -1777,7 +1777,7 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) */ if (!user_has_fpu() && !vmx->vcpu.guest_fpu_loaded) stts(); - load_gdt(&__get_cpu_var(host_gdt)); + load_gdt(this_cpu_ptr(&host_gdt)); } static void vmx_load_host_state(struct vcpu_vmx *vmx) @@ -1807,7 +1807,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) } if (vmx->loaded_vmcs->cpu != cpu) { - struct desc_ptr *gdt = &__get_cpu_var(host_gdt); + struct desc_ptr *gdt = this_cpu_ptr(&host_gdt); unsigned long sysenter_esp; kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); @@ -2744,7 +2744,7 @@ static int hardware_enable(void *garbage) ept_sync_global(); } - native_store_gdt(&__get_cpu_var(host_gdt)); + native_store_gdt(this_cpu_ptr(&host_gdt)); return 0; } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8f1e22d3b286..c84ee536f9a3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1556,7 +1556,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) /* Keep irq disabled to prevent changes to the clock */ local_irq_save(flags); - this_tsc_khz = __get_cpu_var(cpu_tsc_khz); + this_tsc_khz = __this_cpu_read(cpu_tsc_khz); if (unlikely(this_tsc_khz == 0)) { local_irq_restore(flags); kvm_make_request(KVM_REQ_CLOCK_UPDATE, v); diff --git a/arch/x86/mm/kmemcheck/kmemcheck.c b/arch/x86/mm/kmemcheck/kmemcheck.c index dd89a13f1051..b4f2e7e9e907 100644 --- a/arch/x86/mm/kmemcheck/kmemcheck.c +++ b/arch/x86/mm/kmemcheck/kmemcheck.c @@ -140,7 +140,7 @@ static DEFINE_PER_CPU(struct kmemcheck_context, kmemcheck_context); bool kmemcheck_active(struct pt_regs *regs) { - struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + struct kmemcheck_context *data = this_cpu_ptr(&kmemcheck_context); return data->balance > 0; } @@ -148,7 +148,7 @@ bool kmemcheck_active(struct pt_regs *regs) /* Save an address that needs to be shown/hidden */ static void kmemcheck_save_addr(unsigned long addr) { - struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + struct kmemcheck_context *data = this_cpu_ptr(&kmemcheck_context); BUG_ON(data->n_addrs >= ARRAY_SIZE(data->addr)); data->addr[data->n_addrs++] = addr; @@ -156,7 +156,7 @@ static void kmemcheck_save_addr(unsigned long addr) static unsigned int kmemcheck_show_all(void) { - struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + struct kmemcheck_context *data = this_cpu_ptr(&kmemcheck_context); unsigned int i; unsigned int n; @@ -169,7 +169,7 @@ static unsigned int kmemcheck_show_all(void) static unsigned int kmemcheck_hide_all(void) { - struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + struct kmemcheck_context *data = this_cpu_ptr(&kmemcheck_context); unsigned int i; unsigned int n; @@ -185,7 +185,7 @@ static unsigned int kmemcheck_hide_all(void) */ void kmemcheck_show(struct pt_regs *regs) { - struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + struct kmemcheck_context *data = this_cpu_ptr(&kmemcheck_context); BUG_ON(!irqs_disabled()); @@ -226,7 +226,7 @@ void kmemcheck_show(struct pt_regs *regs) */ void kmemcheck_hide(struct pt_regs *regs) { - struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + struct kmemcheck_context *data = this_cpu_ptr(&kmemcheck_context); int n; BUG_ON(!irqs_disabled()); @@ -528,7 +528,7 @@ static void kmemcheck_access(struct pt_regs *regs, const uint8_t *insn_primary; unsigned int size; - struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context); + struct kmemcheck_context *data = this_cpu_ptr(&kmemcheck_context); /* Recursive fault -- ouch. */ if (data->busy) { diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 379e8bd0deea..1d2e6392f5fa 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -64,11 +64,11 @@ u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, static int profile_exceptions_notify(unsigned int val, struct pt_regs *regs) { if (ctr_running) - model->check_ctrs(regs, &__get_cpu_var(cpu_msrs)); + model->check_ctrs(regs, this_cpu_ptr(&cpu_msrs)); else if (!nmi_enabled) return NMI_DONE; else - model->stop(&__get_cpu_var(cpu_msrs)); + model->stop(this_cpu_ptr(&cpu_msrs)); return NMI_HANDLED; } @@ -91,7 +91,7 @@ static void nmi_cpu_save_registers(struct op_msrs *msrs) static void nmi_cpu_start(void *dummy) { - struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); + struct op_msrs const *msrs = this_cpu_ptr(&cpu_msrs); if (!msrs->controls) WARN_ON_ONCE(1); else @@ -111,7 +111,7 @@ static int nmi_start(void) static void nmi_cpu_stop(void *dummy) { - struct op_msrs const *msrs = &__get_cpu_var(cpu_msrs); + struct op_msrs const *msrs = this_cpu_ptr(&cpu_msrs); if (!msrs->controls) WARN_ON_ONCE(1); else diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c index 5c86786bbfd2..a244237f3cfa 100644 --- a/arch/x86/platform/uv/uv_time.c +++ b/arch/x86/platform/uv/uv_time.c @@ -365,7 +365,7 @@ __setup("uvrtcevt", uv_enable_evt_rtc); static __init void uv_rtc_register_clockevents(struct work_struct *dummy) { - struct clock_event_device *ced = &__get_cpu_var(cpu_ced); + struct clock_event_device *ced = this_cpu_ptr(&cpu_ced); *ced = clock_event_device_uv; ced->cpumask = cpumask_of(smp_processor_id()); diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index c0cb11fb5008..2628ee556756 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -821,7 +821,7 @@ static void xen_convert_trap_info(const struct desc_ptr *desc, void xen_copy_trap_info(struct trap_info *traps) { - const struct desc_ptr *desc = &__get_cpu_var(idt_desc); + const struct desc_ptr *desc = this_cpu_ptr(&idt_desc); xen_convert_trap_info(desc, traps); } @@ -838,7 +838,7 @@ static void xen_load_idt(const struct desc_ptr *desc) spin_lock(&lock); - __get_cpu_var(idt_desc) = *desc; + memcpy(this_cpu_ptr(&idt_desc), desc, sizeof(idt_desc)); xen_convert_trap_info(desc, traps); diff --git a/arch/x86/xen/multicalls.c b/arch/x86/xen/multicalls.c index 0d82003e76ad..ea54a08d8301 100644 --- a/arch/x86/xen/multicalls.c +++ b/arch/x86/xen/multicalls.c @@ -54,7 +54,7 @@ DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags); void xen_mc_flush(void) { - struct mc_buffer *b = &__get_cpu_var(mc_buffer); + struct mc_buffer *b = this_cpu_ptr(&mc_buffer); struct multicall_entry *mc; int ret = 0; unsigned long flags; @@ -131,7 +131,7 @@ void xen_mc_flush(void) struct multicall_space __xen_mc_entry(size_t args) { - struct mc_buffer *b = &__get_cpu_var(mc_buffer); + struct mc_buffer *b = this_cpu_ptr(&mc_buffer); struct multicall_space ret; unsigned argidx = roundup(b->argidx, sizeof(u64)); @@ -162,7 +162,7 @@ struct multicall_space __xen_mc_entry(size_t args) struct multicall_space xen_mc_extend_args(unsigned long op, size_t size) { - struct mc_buffer *b = &__get_cpu_var(mc_buffer); + struct mc_buffer *b = this_cpu_ptr(&mc_buffer); struct multicall_space ret = { NULL, NULL }; BUG_ON(preemptible()); @@ -192,7 +192,7 @@ struct multicall_space xen_mc_extend_args(unsigned long op, size_t size) void xen_mc_callback(void (*fn)(void *), void *data) { - struct mc_buffer *b = &__get_cpu_var(mc_buffer); + struct mc_buffer *b = this_cpu_ptr(&mc_buffer); struct callback *cb; if (b->cbidx == MC_BATCH) { diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c index 0ba5f3b967f0..23b45eb9a89c 100644 --- a/arch/x86/xen/spinlock.c +++ b/arch/x86/xen/spinlock.c @@ -109,7 +109,7 @@ static bool xen_pvspin = true; __visible void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want) { int irq = __this_cpu_read(lock_kicker_irq); - struct xen_lock_waiting *w = &__get_cpu_var(lock_waiting); + struct xen_lock_waiting *w = this_cpu_ptr(&lock_waiting); int cpu = smp_processor_id(); u64 start; unsigned long flags; diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 5718b0b58b60..a1d430b112b3 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -80,7 +80,7 @@ static void get_runstate_snapshot(struct vcpu_runstate_info *res) BUG_ON(preemptible()); - state = &__get_cpu_var(xen_runstate); + state = this_cpu_ptr(&xen_runstate); /* * The runstate info is always updated by the hypervisor on @@ -123,7 +123,7 @@ static void do_stolen_accounting(void) WARN_ON(state.state != RUNSTATE_running); - snap = &__get_cpu_var(xen_runstate_snapshot); + snap = this_cpu_ptr(&xen_runstate_snapshot); /* work out how much time the VCPU has not been runn*ing* */ runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable]; @@ -158,7 +158,7 @@ cycle_t xen_clocksource_read(void) cycle_t ret; preempt_disable_notrace(); - src = &__get_cpu_var(xen_vcpu)->time; + src = this_cpu_ptr(&xen_vcpu->time); ret = pvclock_clocksource_read(src); preempt_enable_notrace(); return ret; @@ -397,7 +397,7 @@ static DEFINE_PER_CPU(struct xen_clock_event_device, xen_clock_events) = { .evt. static irqreturn_t xen_timer_interrupt(int irq, void *dev_id) { - struct clock_event_device *evt = &__get_cpu_var(xen_clock_events).evt; + struct clock_event_device *evt = this_cpu_ptr(&xen_clock_events.evt); irqreturn_t ret; ret = IRQ_NONE; @@ -460,7 +460,7 @@ void xen_setup_cpu_clockevents(void) { BUG_ON(preemptible()); - clockevents_register_device(&__get_cpu_var(xen_clock_events).evt); + clockevents_register_device(this_cpu_ptr(&xen_clock_events.evt)); } void xen_timer_resume(void) -- GitLab From e16321709c8270f9803bbfdb51e5e02235078c7f Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:41 -0500 Subject: [PATCH 0659/5088] uv: Replace __get_cpu_var Use __this_cpu_read instead. Cc: Hedi Berriche Cc: Mike Travis Cc: Dimitri Sivanich Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/x86/include/asm/uv/uv_hub.h | 10 ++++---- arch/x86/platform/uv/uv_nmi.c | 40 ++++++++++++++++---------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index bb84cfd5a1a1..a00ad8f2a657 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -601,16 +601,16 @@ struct uv_hub_nmi_s { struct uv_cpu_nmi_s { struct uv_hub_nmi_s *hub; - atomic_t state; - atomic_t pinging; + int state; + int pinging; int queries; int pings; }; -DECLARE_PER_CPU(struct uv_cpu_nmi_s, __uv_cpu_nmi); -#define uv_cpu_nmi (__get_cpu_var(__uv_cpu_nmi)) +DECLARE_PER_CPU(struct uv_cpu_nmi_s, uv_cpu_nmi); + #define uv_hub_nmi (uv_cpu_nmi.hub) -#define uv_cpu_nmi_per(cpu) (per_cpu(__uv_cpu_nmi, cpu)) +#define uv_cpu_nmi_per(cpu) (per_cpu(uv_cpu_nmi, cpu)) #define uv_hub_nmi_per(cpu) (uv_cpu_nmi_per(cpu).hub) /* uv_cpu_nmi_states */ diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c index c89c93320c12..c6b146e67116 100644 --- a/arch/x86/platform/uv/uv_nmi.c +++ b/arch/x86/platform/uv/uv_nmi.c @@ -63,8 +63,8 @@ static struct uv_hub_nmi_s **uv_hub_nmi_list; -DEFINE_PER_CPU(struct uv_cpu_nmi_s, __uv_cpu_nmi); -EXPORT_PER_CPU_SYMBOL_GPL(__uv_cpu_nmi); +DEFINE_PER_CPU(struct uv_cpu_nmi_s, uv_cpu_nmi); +EXPORT_PER_CPU_SYMBOL_GPL(uv_cpu_nmi); static unsigned long nmi_mmr; static unsigned long nmi_mmr_clear; @@ -215,7 +215,7 @@ static int uv_check_nmi(struct uv_hub_nmi_s *hub_nmi) int nmi = 0; local64_inc(&uv_nmi_count); - uv_cpu_nmi.queries++; + this_cpu_inc(uv_cpu_nmi.queries); do { nmi = atomic_read(&hub_nmi->in_nmi); @@ -293,7 +293,7 @@ static void uv_nmi_nr_cpus_ping(void) int cpu; for_each_cpu(cpu, uv_nmi_cpu_mask) - atomic_set(&uv_cpu_nmi_per(cpu).pinging, 1); + uv_cpu_nmi_per(cpu).pinging = 1; apic->send_IPI_mask(uv_nmi_cpu_mask, APIC_DM_NMI); } @@ -304,8 +304,8 @@ static void uv_nmi_cleanup_mask(void) int cpu; for_each_cpu(cpu, uv_nmi_cpu_mask) { - atomic_set(&uv_cpu_nmi_per(cpu).pinging, 0); - atomic_set(&uv_cpu_nmi_per(cpu).state, UV_NMI_STATE_OUT); + uv_cpu_nmi_per(cpu).pinging = 0; + uv_cpu_nmi_per(cpu).state = UV_NMI_STATE_OUT; cpumask_clear_cpu(cpu, uv_nmi_cpu_mask); } } @@ -328,7 +328,7 @@ static int uv_nmi_wait_cpus(int first) int loop_delay = uv_nmi_loop_delay; for_each_cpu(j, uv_nmi_cpu_mask) { - if (atomic_read(&uv_cpu_nmi_per(j).state)) { + if (uv_cpu_nmi_per(j).state) { cpumask_clear_cpu(j, uv_nmi_cpu_mask); if (++k >= n) break; @@ -359,7 +359,7 @@ static int uv_nmi_wait_cpus(int first) static void uv_nmi_wait(int master) { /* indicate this cpu is in */ - atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_IN); + this_cpu_write(uv_cpu_nmi.state, UV_NMI_STATE_IN); /* if not the first cpu in (the master), then we are a slave cpu */ if (!master) @@ -419,7 +419,7 @@ static void uv_nmi_dump_state_cpu(int cpu, struct pt_regs *regs) "UV:%sNMI process trace for CPU %d\n", dots, cpu); show_regs(regs); } - atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_DUMP_DONE); + this_cpu_write(uv_cpu_nmi.state, UV_NMI_STATE_DUMP_DONE); } /* Trigger a slave cpu to dump it's state */ @@ -427,20 +427,20 @@ static void uv_nmi_trigger_dump(int cpu) { int retry = uv_nmi_trigger_delay; - if (atomic_read(&uv_cpu_nmi_per(cpu).state) != UV_NMI_STATE_IN) + if (uv_cpu_nmi_per(cpu).state != UV_NMI_STATE_IN) return; - atomic_set(&uv_cpu_nmi_per(cpu).state, UV_NMI_STATE_DUMP); + uv_cpu_nmi_per(cpu).state = UV_NMI_STATE_DUMP; do { cpu_relax(); udelay(10); - if (atomic_read(&uv_cpu_nmi_per(cpu).state) + if (uv_cpu_nmi_per(cpu).state != UV_NMI_STATE_DUMP) return; } while (--retry > 0); pr_crit("UV: CPU %d stuck in process dump function\n", cpu); - atomic_set(&uv_cpu_nmi_per(cpu).state, UV_NMI_STATE_DUMP_DONE); + uv_cpu_nmi_per(cpu).state = UV_NMI_STATE_DUMP_DONE; } /* Wait until all cpus ready to exit */ @@ -488,7 +488,7 @@ static void uv_nmi_dump_state(int cpu, struct pt_regs *regs, int master) } else { while (!atomic_read(&uv_nmi_slave_continue)) cpu_relax(); - while (atomic_read(&uv_cpu_nmi.state) != UV_NMI_STATE_DUMP) + while (this_cpu_read(uv_cpu_nmi.state) != UV_NMI_STATE_DUMP) cpu_relax(); uv_nmi_dump_state_cpu(cpu, regs); } @@ -615,7 +615,7 @@ int uv_handle_nmi(unsigned int reason, struct pt_regs *regs) local_irq_save(flags); /* If not a UV System NMI, ignore */ - if (!atomic_read(&uv_cpu_nmi.pinging) && !uv_check_nmi(hub_nmi)) { + if (!this_cpu_read(uv_cpu_nmi.pinging) && !uv_check_nmi(hub_nmi)) { local_irq_restore(flags); return NMI_DONE; } @@ -639,7 +639,7 @@ int uv_handle_nmi(unsigned int reason, struct pt_regs *regs) uv_call_kgdb_kdb(cpu, regs, master); /* Clear per_cpu "in nmi" flag */ - atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_OUT); + this_cpu_write(uv_cpu_nmi.state, UV_NMI_STATE_OUT); /* Clear MMR NMI flag on each hub */ uv_clear_nmi(cpu); @@ -666,16 +666,16 @@ static int uv_handle_nmi_ping(unsigned int reason, struct pt_regs *regs) { int ret; - uv_cpu_nmi.queries++; - if (!atomic_read(&uv_cpu_nmi.pinging)) { + this_cpu_inc(uv_cpu_nmi.queries); + if (!this_cpu_read(uv_cpu_nmi.pinging)) { local64_inc(&uv_nmi_ping_misses); return NMI_DONE; } - uv_cpu_nmi.pings++; + this_cpu_inc(uv_cpu_nmi.pings); local64_inc(&uv_nmi_ping_count); ret = uv_handle_nmi(reason, regs); - atomic_set(&uv_cpu_nmi.pinging, 0); + this_cpu_write(uv_cpu_nmi.pinging, 0); return ret; } -- GitLab From 06b96c8beb940619ddc818e2e00915fbc524f807 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:42 -0500 Subject: [PATCH 0660/5088] arm: Replace __this_cpu_ptr with raw_cpu_ptr __this_cpu_ptr is being phased out. So replace with raw_cpu_ptr. Cc: Russell King Cc: Catalin Marinas Acked-by: Will Deacon Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/arm/kernel/smp_twd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index dfc32130bc44..93090213c71c 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -92,7 +92,7 @@ static int twd_timer_ack(void) static void twd_timer_stop(void) { - struct clock_event_device *clk = __this_cpu_ptr(twd_evt); + struct clock_event_device *clk = raw_cpu_ptr(twd_evt); twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk); disable_percpu_irq(clk->irq); @@ -108,7 +108,7 @@ static void twd_update_frequency(void *new_rate) { twd_timer_rate = *((unsigned long *) new_rate); - clockevents_update_freq(__this_cpu_ptr(twd_evt), twd_timer_rate); + clockevents_update_freq(raw_cpu_ptr(twd_evt), twd_timer_rate); } static int twd_rate_change(struct notifier_block *nb, @@ -134,7 +134,7 @@ static struct notifier_block twd_clk_nb = { static int twd_clk_init(void) { - if (twd_evt && __this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) + if (twd_evt && raw_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) return clk_notifier_register(twd_clk, &twd_clk_nb); return 0; @@ -153,7 +153,7 @@ static void twd_update_frequency(void *data) { twd_timer_rate = clk_get_rate(twd_clk); - clockevents_update_freq(__this_cpu_ptr(twd_evt), twd_timer_rate); + clockevents_update_freq(raw_cpu_ptr(twd_evt), twd_timer_rate); } static int twd_cpufreq_transition(struct notifier_block *nb, @@ -179,7 +179,7 @@ static struct notifier_block twd_cpufreq_nb = { static int twd_cpufreq_init(void) { - if (twd_evt && __this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) + if (twd_evt && raw_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) return cpufreq_register_notifier(&twd_cpufreq_nb, CPUFREQ_TRANSITION_NOTIFIER); @@ -269,7 +269,7 @@ static void twd_get_clock(struct device_node *np) */ static void twd_timer_setup(void) { - struct clock_event_device *clk = __this_cpu_ptr(twd_evt); + struct clock_event_device *clk = raw_cpu_ptr(twd_evt); int cpu = smp_processor_id(); /* -- GitLab From d1cd39ad583e36f3a945ba043a0a2bfae83fe859 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:43 -0500 Subject: [PATCH 0661/5088] MIPS: Replace __get_cpu_var uses in FPU emulator. The use of __this_cpu_inc() requires a fundamental integer type, so change the type of all the counters to unsigned long, which is the same width they were before, but not wrapped in local_t. Signed-off-by: David Daney Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/mips/include/asm/fpu_emulator.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/mips/include/asm/fpu_emulator.h b/arch/mips/include/asm/fpu_emulator.h index 0195745b4b1b..3ee347713307 100644 --- a/arch/mips/include/asm/fpu_emulator.h +++ b/arch/mips/include/asm/fpu_emulator.h @@ -33,17 +33,17 @@ #ifdef CONFIG_DEBUG_FS struct mips_fpu_emulator_stats { - local_t emulated; - local_t loads; - local_t stores; - local_t cp1ops; - local_t cp1xops; - local_t errors; - local_t ieee754_inexact; - local_t ieee754_underflow; - local_t ieee754_overflow; - local_t ieee754_zerodiv; - local_t ieee754_invalidop; + unsigned long emulated; + unsigned long loads; + unsigned long stores; + unsigned long cp1ops; + unsigned long cp1xops; + unsigned long errors; + unsigned long ieee754_inexact; + unsigned long ieee754_underflow; + unsigned long ieee754_overflow; + unsigned long ieee754_zerodiv; + unsigned long ieee754_invalidop; }; DECLARE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); @@ -51,7 +51,7 @@ DECLARE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); #define MIPS_FPU_EMU_INC_STATS(M) \ do { \ preempt_disable(); \ - __local_inc(&__get_cpu_var(fpuemustats).M); \ + __this_cpu_inc(fpuemustats.M); \ preempt_enable(); \ } while (0) -- GitLab From 35898716b4d3382791d219be317faace580b6a41 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:44 -0500 Subject: [PATCH 0662/5088] mips: Replace __get_cpu_var uses __get_cpu_var() is used for multiple purposes in the kernel source. One of them is address calculation via the form &__get_cpu_var(x). This calculates the address for the instance of the percpu variable of the current processor based on an offset. Other use cases are for storing and retrieving data from the current processors percpu area. __get_cpu_var() can be used as an lvalue when writing data or on the right side of an assignment. __get_cpu_var() is defined as : #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) __get_cpu_var() always only does an address determination. However, store and retrieve operations could use a segment prefix (or global register on other platforms) to avoid the address calculation. this_cpu_write() and this_cpu_read() can directly take an offset into a percpu area and use optimized assembly code to read and write per cpu variables. This patch converts __get_cpu_var into either an explicit address calculation using this_cpu_ptr() or into a use of this_cpu operations that use the offset. Thereby address calculations are avoided and less registers are used when code is generated. At the end of the patch set all uses of __get_cpu_var have been removed so the macro is removed too. The patch set includes passes over all arches as well. Once these operations are used throughout then specialized macros can be defined in non -x86 arches as well in order to optimize per cpu access by f.e. using a global register that may be set to the per cpu base. Transformations done to __get_cpu_var() 1. Determine the address of the percpu instance of the current processor. DEFINE_PER_CPU(int, y); int *x = &__get_cpu_var(y); Converts to int *x = this_cpu_ptr(&y); 2. Same as #1 but this time an array structure is involved. DEFINE_PER_CPU(int, y[20]); int *x = __get_cpu_var(y); Converts to int *x = this_cpu_ptr(y); 3. Retrieve the content of the current processors instance of a per cpu variable. DEFINE_PER_CPU(int, y); int x = __get_cpu_var(y) Converts to int x = __this_cpu_read(y); 4. Retrieve the content of a percpu struct DEFINE_PER_CPU(struct mystruct, y); struct mystruct x = __get_cpu_var(y); Converts to memcpy(&x, this_cpu_ptr(&y), sizeof(x)); 5. Assignment to a per cpu variable DEFINE_PER_CPU(int, y) __get_cpu_var(y) = x; Converts to __this_cpu_write(y, x); 6. Increment/Decrement etc of a per cpu variable DEFINE_PER_CPU(int, y); __get_cpu_var(y)++ Converts to __this_cpu_inc(y) Cc: Ralf Baechle Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/mips/cavium-octeon/octeon-irq.c | 30 ++++++++++++++-------------- arch/mips/kernel/kprobes.c | 6 +++--- arch/mips/kernel/perf_event_mipsxx.c | 14 ++++++------- arch/mips/kernel/smp-bmips.c | 2 +- arch/mips/loongson/loongson-3/smp.c | 6 +++--- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 1b82ac6921e0..741734049675 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -264,13 +264,13 @@ static void octeon_irq_ciu_enable_local(struct irq_data *data) unsigned long *pen; unsigned long flags; union octeon_ciu_chip_data cd; - raw_spinlock_t *lock = &__get_cpu_var(octeon_irq_ciu_spinlock); + raw_spinlock_t *lock = this_cpu_ptr(&octeon_irq_ciu_spinlock); cd.p = irq_data_get_irq_chip_data(data); raw_spin_lock_irqsave(lock, flags); if (cd.s.line == 0) { - pen = &__get_cpu_var(octeon_irq_ciu0_en_mirror); + pen = this_cpu_ptr(&octeon_irq_ciu0_en_mirror); __set_bit(cd.s.bit, pen); /* * Must be visible to octeon_irq_ip{2,3}_ciu() before @@ -279,7 +279,7 @@ static void octeon_irq_ciu_enable_local(struct irq_data *data) wmb(); cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num() * 2), *pen); } else { - pen = &__get_cpu_var(octeon_irq_ciu1_en_mirror); + pen = this_cpu_ptr(&octeon_irq_ciu1_en_mirror); __set_bit(cd.s.bit, pen); /* * Must be visible to octeon_irq_ip{2,3}_ciu() before @@ -296,13 +296,13 @@ static void octeon_irq_ciu_disable_local(struct irq_data *data) unsigned long *pen; unsigned long flags; union octeon_ciu_chip_data cd; - raw_spinlock_t *lock = &__get_cpu_var(octeon_irq_ciu_spinlock); + raw_spinlock_t *lock = this_cpu_ptr(&octeon_irq_ciu_spinlock); cd.p = irq_data_get_irq_chip_data(data); raw_spin_lock_irqsave(lock, flags); if (cd.s.line == 0) { - pen = &__get_cpu_var(octeon_irq_ciu0_en_mirror); + pen = this_cpu_ptr(&octeon_irq_ciu0_en_mirror); __clear_bit(cd.s.bit, pen); /* * Must be visible to octeon_irq_ip{2,3}_ciu() before @@ -311,7 +311,7 @@ static void octeon_irq_ciu_disable_local(struct irq_data *data) wmb(); cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num() * 2), *pen); } else { - pen = &__get_cpu_var(octeon_irq_ciu1_en_mirror); + pen = this_cpu_ptr(&octeon_irq_ciu1_en_mirror); __clear_bit(cd.s.bit, pen); /* * Must be visible to octeon_irq_ip{2,3}_ciu() before @@ -431,11 +431,11 @@ static void octeon_irq_ciu_enable_local_v2(struct irq_data *data) if (cd.s.line == 0) { int index = cvmx_get_core_num() * 2; - set_bit(cd.s.bit, &__get_cpu_var(octeon_irq_ciu0_en_mirror)); + set_bit(cd.s.bit, this_cpu_ptr(&octeon_irq_ciu0_en_mirror)); cvmx_write_csr(CVMX_CIU_INTX_EN0_W1S(index), mask); } else { int index = cvmx_get_core_num() * 2 + 1; - set_bit(cd.s.bit, &__get_cpu_var(octeon_irq_ciu1_en_mirror)); + set_bit(cd.s.bit, this_cpu_ptr(&octeon_irq_ciu1_en_mirror)); cvmx_write_csr(CVMX_CIU_INTX_EN1_W1S(index), mask); } } @@ -450,11 +450,11 @@ static void octeon_irq_ciu_disable_local_v2(struct irq_data *data) if (cd.s.line == 0) { int index = cvmx_get_core_num() * 2; - clear_bit(cd.s.bit, &__get_cpu_var(octeon_irq_ciu0_en_mirror)); + clear_bit(cd.s.bit, this_cpu_ptr(&octeon_irq_ciu0_en_mirror)); cvmx_write_csr(CVMX_CIU_INTX_EN0_W1C(index), mask); } else { int index = cvmx_get_core_num() * 2 + 1; - clear_bit(cd.s.bit, &__get_cpu_var(octeon_irq_ciu1_en_mirror)); + clear_bit(cd.s.bit, this_cpu_ptr(&octeon_irq_ciu1_en_mirror)); cvmx_write_csr(CVMX_CIU_INTX_EN1_W1C(index), mask); } } @@ -1063,7 +1063,7 @@ static void octeon_irq_ip2_ciu(void) const unsigned long core_id = cvmx_get_core_num(); u64 ciu_sum = cvmx_read_csr(CVMX_CIU_INTX_SUM0(core_id * 2)); - ciu_sum &= __get_cpu_var(octeon_irq_ciu0_en_mirror); + ciu_sum &= __this_cpu_read(octeon_irq_ciu0_en_mirror); if (likely(ciu_sum)) { int bit = fls64(ciu_sum) - 1; int irq = octeon_irq_ciu_to_irq[0][bit]; @@ -1080,7 +1080,7 @@ static void octeon_irq_ip3_ciu(void) { u64 ciu_sum = cvmx_read_csr(CVMX_CIU_INT_SUM1); - ciu_sum &= __get_cpu_var(octeon_irq_ciu1_en_mirror); + ciu_sum &= __this_cpu_read(octeon_irq_ciu1_en_mirror); if (likely(ciu_sum)) { int bit = fls64(ciu_sum) - 1; int irq = octeon_irq_ciu_to_irq[1][bit]; @@ -1129,10 +1129,10 @@ static void octeon_irq_init_ciu_percpu(void) int coreid = cvmx_get_core_num(); - __get_cpu_var(octeon_irq_ciu0_en_mirror) = 0; - __get_cpu_var(octeon_irq_ciu1_en_mirror) = 0; + __this_cpu_write(octeon_irq_ciu0_en_mirror, 0); + __this_cpu_write(octeon_irq_ciu1_en_mirror, 0); wmb(); - raw_spin_lock_init(&__get_cpu_var(octeon_irq_ciu_spinlock)); + raw_spin_lock_init(this_cpu_ptr(&octeon_irq_ciu_spinlock)); /* * Disable All CIU Interrupts. The ones we need will be * enabled later. Read the SUM register so we know the write diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c index 1f8187ab0997..212f46f2014e 100644 --- a/arch/mips/kernel/kprobes.c +++ b/arch/mips/kernel/kprobes.c @@ -224,7 +224,7 @@ static void save_previous_kprobe(struct kprobe_ctlblk *kcb) static void restore_previous_kprobe(struct kprobe_ctlblk *kcb) { - __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); kcb->kprobe_status = kcb->prev_kprobe.status; kcb->kprobe_old_SR = kcb->prev_kprobe.old_SR; kcb->kprobe_saved_SR = kcb->prev_kprobe.saved_SR; @@ -234,7 +234,7 @@ static void restore_previous_kprobe(struct kprobe_ctlblk *kcb) static void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { - __get_cpu_var(current_kprobe) = p; + __this_cpu_write(current_kprobe, p); kcb->kprobe_saved_SR = kcb->kprobe_old_SR = (regs->cp0_status & ST0_IE); kcb->kprobe_saved_epc = regs->cp0_epc; } @@ -385,7 +385,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) ret = 1; goto no_kprobe; } - p = __get_cpu_var(current_kprobe); + p = __this_cpu_read(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) goto ss_probe; } diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index 14bf74b0f51c..abb209fa28c6 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -340,7 +340,7 @@ static int mipsxx_pmu_alloc_counter(struct cpu_hw_events *cpuc, static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); WARN_ON(idx < 0 || idx >= mipspmu.num_counters); @@ -360,7 +360,7 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx) static void mipsxx_pmu_disable_event(int idx) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); unsigned long flags; WARN_ON(idx < 0 || idx >= mipspmu.num_counters); @@ -460,7 +460,7 @@ static void mipspmu_stop(struct perf_event *event, int flags) static int mipspmu_add(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; int idx; int err = 0; @@ -496,7 +496,7 @@ static int mipspmu_add(struct perf_event *event, int flags) static void mipspmu_del(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; @@ -1275,7 +1275,7 @@ static int __hw_perf_event_init(struct perf_event *event) static void pause_local_counters(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int ctr = mipspmu.num_counters; unsigned long flags; @@ -1291,7 +1291,7 @@ static void pause_local_counters(void) static void resume_local_counters(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int ctr = mipspmu.num_counters; do { @@ -1302,7 +1302,7 @@ static void resume_local_counters(void) static int mipsxx_pmu_handle_shared_irq(void) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct perf_sample_data data; unsigned int counters = mipspmu.num_counters; u64 counter; diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index df9e2bd9b2c2..06bb5ed6d80a 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -346,7 +346,7 @@ static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id) int action, cpu = irq - IPI0_IRQ; spin_lock_irqsave(&ipi_lock, flags); - action = __get_cpu_var(ipi_action_mask); + action = __this_cpu_read(ipi_action_mask); per_cpu(ipi_action_mask, cpu) = 0; clear_c0_cause(cpu ? C_SW1 : C_SW0); spin_unlock_irqrestore(&ipi_lock, flags); diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c index 74e827b4ec8f..d8c63af6c7cc 100644 --- a/arch/mips/loongson/loongson-3/smp.c +++ b/arch/mips/loongson/loongson-3/smp.c @@ -299,16 +299,16 @@ static void loongson3_init_secondary(void) per_cpu(cpu_state, cpu) = CPU_ONLINE; i = 0; - __get_cpu_var(core0_c0count) = 0; + __this_cpu_write(core0_c0count, 0); loongson3_send_ipi_single(0, SMP_ASK_C0COUNT); - while (!__get_cpu_var(core0_c0count)) { + while (!__this_cpu_read(core0_c0count)) { i++; cpu_relax(); } if (i > MAX_LOOPS) i = MAX_LOOPS; - initcount = __get_cpu_var(core0_c0count) + i; + initcount = __this_cpu_read(core0_c0count) + i; write_c0_count(initcount); } -- GitLab From eb7e7d766326f70859046bfdb6277068c2461fe2 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:45 -0500 Subject: [PATCH 0663/5088] s390: Replace __get_cpu_var uses __get_cpu_var() is used for multiple purposes in the kernel source. One of them is address calculation via the form &__get_cpu_var(x). This calculates the address for the instance of the percpu variable of the current processor based on an offset. Other use cases are for storing and retrieving data from the current processors percpu area. __get_cpu_var() can be used as an lvalue when writing data or on the right side of an assignment. __get_cpu_var() is defined as : #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) __get_cpu_var() always only does an address determination. However, store and retrieve operations could use a segment prefix (or global register on other platforms) to avoid the address calculation. this_cpu_write() and this_cpu_read() can directly take an offset into a percpu area and use optimized assembly code to read and write per cpu variables. This patch converts __get_cpu_var into either an explicit address calculation using this_cpu_ptr() or into a use of this_cpu operations that use the offset. Thereby address calculations are avoided and less registers are used when code is generated. At the end of the patch set all uses of __get_cpu_var have been removed so the macro is removed too. The patch set includes passes over all arches as well. Once these operations are used throughout then specialized macros can be defined in non -x86 arches as well in order to optimize per cpu access by f.e. using a global register that may be set to the per cpu base. Transformations done to __get_cpu_var() 1. Determine the address of the percpu instance of the current processor. DEFINE_PER_CPU(int, y); int *x = &__get_cpu_var(y); Converts to int *x = this_cpu_ptr(&y); 2. Same as #1 but this time an array structure is involved. DEFINE_PER_CPU(int, y[20]); int *x = __get_cpu_var(y); Converts to int *x = this_cpu_ptr(y); 3. Retrieve the content of the current processors instance of a per cpu variable. DEFINE_PER_CPU(int, y); int x = __get_cpu_var(y) Converts to int x = __this_cpu_read(y); 4. Retrieve the content of a percpu struct DEFINE_PER_CPU(struct mystruct, y); struct mystruct x = __get_cpu_var(y); Converts to memcpy(&x, this_cpu_ptr(&y), sizeof(x)); 5. Assignment to a per cpu variable DEFINE_PER_CPU(int, y) __get_cpu_var(y) = x; Converts to this_cpu_write(y, x); 6. Increment/Decrement etc of a per cpu variable DEFINE_PER_CPU(int, y); __get_cpu_var(y)++ Converts to this_cpu_inc(y) Cc: Martin Schwidefsky CC: linux390@de.ibm.com Acked-by: Heiko Carstens Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/s390/include/asm/cputime.h | 2 +- arch/s390/include/asm/irq.h | 2 +- arch/s390/include/asm/percpu.h | 16 ++++++++-------- arch/s390/kernel/irq.c | 2 +- arch/s390/kernel/kprobes.c | 8 ++++---- arch/s390/kernel/nmi.c | 10 +++++++--- arch/s390/kernel/perf_cpum_cf.c | 22 +++++++++++----------- arch/s390/kernel/perf_cpum_sf.c | 16 ++++++++-------- arch/s390/kernel/processor.c | 4 ++-- arch/s390/kernel/time.c | 6 +++--- arch/s390/kernel/vtime.c | 2 +- arch/s390/oprofile/hwsampler.c | 2 +- 12 files changed, 48 insertions(+), 44 deletions(-) diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index f65bd3634519..692d310dc32d 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h @@ -184,7 +184,7 @@ cputime64_t s390_get_idle_time(int cpu); static inline int s390_nohz_delay(int cpu) { - return __get_cpu_var(s390_idle).nohz_delay != 0; + return __this_cpu_read(s390_idle.nohz_delay) != 0; } #define arch_needs_cpu(cpu) s390_nohz_delay(cpu) diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index c4dd400a2791..713d325afbfe 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -81,7 +81,7 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat); static __always_inline void inc_irq_stat(enum interruption_class irq) { - __get_cpu_var(irq_stat).irqs[irq]++; + __this_cpu_inc(irq_stat.irqs[irq]); } struct ext_code { diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h index fa91e0097458..933355e0d091 100644 --- a/arch/s390/include/asm/percpu.h +++ b/arch/s390/include/asm/percpu.h @@ -31,7 +31,7 @@ pcp_op_T__ old__, new__, prev__; \ pcp_op_T__ *ptr__; \ preempt_disable(); \ - ptr__ = __this_cpu_ptr(&(pcp)); \ + ptr__ = raw_cpu_ptr(&(pcp)); \ prev__ = *ptr__; \ do { \ old__ = prev__; \ @@ -70,7 +70,7 @@ pcp_op_T__ val__ = (val); \ pcp_op_T__ old__, *ptr__; \ preempt_disable(); \ - ptr__ = __this_cpu_ptr(&(pcp)); \ + ptr__ = raw_cpu_ptr(&(pcp)); \ if (__builtin_constant_p(val__) && \ ((szcast)val__ > -129) && ((szcast)val__ < 128)) { \ asm volatile( \ @@ -97,7 +97,7 @@ pcp_op_T__ val__ = (val); \ pcp_op_T__ old__, *ptr__; \ preempt_disable(); \ - ptr__ = __this_cpu_ptr(&(pcp)); \ + ptr__ = raw_cpu_ptr(&(pcp)); \ asm volatile( \ op " %[old__],%[val__],%[ptr__]\n" \ : [old__] "=d" (old__), [ptr__] "+Q" (*ptr__) \ @@ -116,7 +116,7 @@ pcp_op_T__ val__ = (val); \ pcp_op_T__ old__, *ptr__; \ preempt_disable(); \ - ptr__ = __this_cpu_ptr(&(pcp)); \ + ptr__ = raw_cpu_ptr(&(pcp)); \ asm volatile( \ op " %[old__],%[val__],%[ptr__]\n" \ : [old__] "=d" (old__), [ptr__] "+Q" (*ptr__) \ @@ -138,7 +138,7 @@ pcp_op_T__ ret__; \ pcp_op_T__ *ptr__; \ preempt_disable(); \ - ptr__ = __this_cpu_ptr(&(pcp)); \ + ptr__ = raw_cpu_ptr(&(pcp)); \ ret__ = cmpxchg(ptr__, oval, nval); \ preempt_enable(); \ ret__; \ @@ -154,7 +154,7 @@ typeof(pcp) *ptr__; \ typeof(pcp) ret__; \ preempt_disable(); \ - ptr__ = __this_cpu_ptr(&(pcp)); \ + ptr__ = raw_cpu_ptr(&(pcp)); \ ret__ = xchg(ptr__, nval); \ preempt_enable(); \ ret__; \ @@ -173,8 +173,8 @@ typeof(pcp2) *p2__; \ int ret__; \ preempt_disable(); \ - p1__ = __this_cpu_ptr(&(pcp1)); \ - p2__ = __this_cpu_ptr(&(pcp2)); \ + p1__ = raw_cpu_ptr(&(pcp1)); \ + p2__ = raw_cpu_ptr(&(pcp2)); \ ret__ = __cmpxchg_double(p1__, p2__, o1__, o2__, n1__, n2__); \ preempt_enable(); \ ret__; \ diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 8eb82443cfbd..891c183211ce 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -258,7 +258,7 @@ static irqreturn_t do_ext_interrupt(int irq, void *dummy) ext_code = *(struct ext_code *) ®s->int_code; if (ext_code.code != EXT_IRQ_CLK_COMP) - __get_cpu_var(s390_idle).nohz_delay = 1; + __this_cpu_write(s390_idle.nohz_delay, 1); index = ext_hash(ext_code.code); rcu_read_lock(); diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index bc71a7b95af5..131ed342ed10 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -366,9 +366,9 @@ static void __kprobes disable_singlestep(struct kprobe_ctlblk *kcb, */ static void __kprobes push_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p) { - kcb->prev_kprobe.kp = __get_cpu_var(current_kprobe); + kcb->prev_kprobe.kp = __this_cpu_read(current_kprobe); kcb->prev_kprobe.status = kcb->kprobe_status; - __get_cpu_var(current_kprobe) = p; + __this_cpu_write(current_kprobe, p); } /* @@ -378,7 +378,7 @@ static void __kprobes push_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p) */ static void __kprobes pop_kprobe(struct kprobe_ctlblk *kcb) { - __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); kcb->kprobe_status = kcb->prev_kprobe.status; } @@ -459,7 +459,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) enable_singlestep(kcb, regs, (unsigned long) p->ainsn.insn); return 1; } else if (kprobe_running()) { - p = __get_cpu_var(current_kprobe); + p = __this_cpu_read(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) { /* * Continuation after the jprobe completed and diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 210e1285f75a..d75c42f4147d 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -53,8 +53,12 @@ void s390_handle_mcck(void) */ local_irq_save(flags); local_mcck_disable(); - mcck = __get_cpu_var(cpu_mcck); - memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct)); + /* + * Ummm... Does this make sense at all? Copying the percpu struct + * and then zapping it one statement later? + */ + memcpy(&mcck, this_cpu_ptr(&cpu_mcck), sizeof(mcck)); + memset(&mcck, 0, sizeof(struct mcck_struct)); clear_cpu_flag(CIF_MCCK_PENDING); local_mcck_enable(); local_irq_restore(flags); @@ -253,7 +257,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs) nmi_enter(); inc_irq_stat(NMI_NMI); mci = (struct mci *) &S390_lowcore.mcck_interruption_code; - mcck = &__get_cpu_var(cpu_mcck); + mcck = this_cpu_ptr(&cpu_mcck); umode = user_mode(regs); if (mci->sd) { diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index d3194de7ae1e..56fdad479115 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c @@ -173,7 +173,7 @@ static int validate_ctr_auth(const struct hw_perf_event *hwc) */ static void cpumf_pmu_enable(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); int err; if (cpuhw->flags & PMU_F_ENABLED) @@ -196,7 +196,7 @@ static void cpumf_pmu_enable(struct pmu *pmu) */ static void cpumf_pmu_disable(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); int err; u64 inactive; @@ -230,7 +230,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code, return; inc_irq_stat(IRQEXT_CMC); - cpuhw = &__get_cpu_var(cpu_hw_events); + cpuhw = this_cpu_ptr(&cpu_hw_events); /* Measurement alerts are shared and might happen when the PMU * is not reserved. Ignore these alerts in this case. */ @@ -250,7 +250,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code, #define PMC_RELEASE 1 static void setup_pmc_cpu(void *flags) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); switch (*((int *) flags)) { case PMC_INIT: @@ -475,7 +475,7 @@ static void cpumf_pmu_read(struct perf_event *event) static void cpumf_pmu_start(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED))) @@ -506,7 +506,7 @@ static void cpumf_pmu_start(struct perf_event *event, int flags) static void cpumf_pmu_stop(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; if (!(hwc->state & PERF_HES_STOPPED)) { @@ -527,7 +527,7 @@ static void cpumf_pmu_stop(struct perf_event *event, int flags) static int cpumf_pmu_add(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); /* Check authorization for the counter set to which this * counter belongs. @@ -551,7 +551,7 @@ static int cpumf_pmu_add(struct perf_event *event, int flags) static void cpumf_pmu_del(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); cpumf_pmu_stop(event, PERF_EF_UPDATE); @@ -575,7 +575,7 @@ static void cpumf_pmu_del(struct perf_event *event, int flags) */ static void cpumf_pmu_start_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); perf_pmu_disable(pmu); cpuhw->flags |= PERF_EVENT_TXN; @@ -589,7 +589,7 @@ static void cpumf_pmu_start_txn(struct pmu *pmu) */ static void cpumf_pmu_cancel_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); WARN_ON(cpuhw->tx_state != cpuhw->state); @@ -604,7 +604,7 @@ static void cpumf_pmu_cancel_txn(struct pmu *pmu) */ static int cpumf_pmu_commit_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); u64 state; /* check if the updated state can be scheduled */ diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index ea0c7b2ef030..08e761318c17 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -562,7 +562,7 @@ static DEFINE_MUTEX(pmc_reserve_mutex); static void setup_pmc_cpu(void *flags) { int err; - struct cpu_hw_sf *cpusf = &__get_cpu_var(cpu_hw_sf); + struct cpu_hw_sf *cpusf = this_cpu_ptr(&cpu_hw_sf); err = 0; switch (*((int *) flags)) { @@ -849,7 +849,7 @@ static int cpumsf_pmu_event_init(struct perf_event *event) static void cpumsf_pmu_enable(struct pmu *pmu) { - struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); + struct cpu_hw_sf *cpuhw = this_cpu_ptr(&cpu_hw_sf); struct hw_perf_event *hwc; int err; @@ -898,7 +898,7 @@ static void cpumsf_pmu_enable(struct pmu *pmu) static void cpumsf_pmu_disable(struct pmu *pmu) { - struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); + struct cpu_hw_sf *cpuhw = this_cpu_ptr(&cpu_hw_sf); struct hws_lsctl_request_block inactive; struct hws_qsi_info_block si; int err; @@ -1306,7 +1306,7 @@ static void cpumsf_pmu_read(struct perf_event *event) */ static void cpumsf_pmu_start(struct perf_event *event, int flags) { - struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); + struct cpu_hw_sf *cpuhw = this_cpu_ptr(&cpu_hw_sf); if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) return; @@ -1327,7 +1327,7 @@ static void cpumsf_pmu_start(struct perf_event *event, int flags) */ static void cpumsf_pmu_stop(struct perf_event *event, int flags) { - struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); + struct cpu_hw_sf *cpuhw = this_cpu_ptr(&cpu_hw_sf); if (event->hw.state & PERF_HES_STOPPED) return; @@ -1346,7 +1346,7 @@ static void cpumsf_pmu_stop(struct perf_event *event, int flags) static int cpumsf_pmu_add(struct perf_event *event, int flags) { - struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); + struct cpu_hw_sf *cpuhw = this_cpu_ptr(&cpu_hw_sf); int err; if (cpuhw->flags & PMU_F_IN_USE) @@ -1397,7 +1397,7 @@ static int cpumsf_pmu_add(struct perf_event *event, int flags) static void cpumsf_pmu_del(struct perf_event *event, int flags) { - struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); + struct cpu_hw_sf *cpuhw = this_cpu_ptr(&cpu_hw_sf); perf_pmu_disable(event->pmu); cpumsf_pmu_stop(event, PERF_EF_UPDATE); @@ -1470,7 +1470,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code, if (!(alert & CPU_MF_INT_SF_MASK)) return; inc_irq_stat(IRQEXT_CMS); - cpuhw = &__get_cpu_var(cpu_hw_sf); + cpuhw = this_cpu_ptr(&cpu_hw_sf); /* Measurement alerts are shared and might happen when the PMU * is not reserved. Ignore these alerts in this case. */ diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 24612029f450..f0305b1189aa 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -23,8 +23,8 @@ static DEFINE_PER_CPU(struct cpuid, cpu_id); */ void cpu_init(void) { - struct s390_idle_data *idle = &__get_cpu_var(s390_idle); - struct cpuid *id = &__get_cpu_var(cpu_id); + struct s390_idle_data *idle = this_cpu_ptr(&s390_idle); + struct cpuid *id = this_cpu_ptr(&cpu_id); get_cpu_id(id); atomic_inc(&init_mm.mm_count); diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 4cef607f3711..4e5a6d881c62 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -92,7 +92,7 @@ void clock_comparator_work(void) struct clock_event_device *cd; S390_lowcore.clock_comparator = -1ULL; - cd = &__get_cpu_var(comparators); + cd = this_cpu_ptr(&comparators); cd->event_handler(cd); } @@ -360,7 +360,7 @@ EXPORT_SYMBOL(get_sync_clock); */ static void disable_sync_clock(void *dummy) { - atomic_t *sw_ptr = &__get_cpu_var(clock_sync_word); + atomic_t *sw_ptr = this_cpu_ptr(&clock_sync_word); /* * Clear the in-sync bit 2^31. All get_sync_clock calls will * fail until the sync bit is turned back on. In addition @@ -377,7 +377,7 @@ static void disable_sync_clock(void *dummy) */ static void enable_sync_clock(void) { - atomic_t *sw_ptr = &__get_cpu_var(clock_sync_word); + atomic_t *sw_ptr = this_cpu_ptr(&clock_sync_word); atomic_set_mask(0x80000000, sw_ptr); } diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 8c34363d6f1e..f400745dedc0 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -154,7 +154,7 @@ EXPORT_SYMBOL_GPL(vtime_account_system); void __kprobes vtime_stop_cpu(void) { - struct s390_idle_data *idle = &__get_cpu_var(s390_idle); + struct s390_idle_data *idle = this_cpu_ptr(&s390_idle); unsigned long long idle_time; unsigned long psw_mask; diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c index e53c6f268807..ff9b4eb34589 100644 --- a/arch/s390/oprofile/hwsampler.c +++ b/arch/s390/oprofile/hwsampler.c @@ -178,7 +178,7 @@ static int smp_ctl_qsi(int cpu) static void hws_ext_handler(struct ext_code ext_code, unsigned int param32, unsigned long param64) { - struct hws_cpu_buffer *cb = &__get_cpu_var(sampler_cpu_buffer); + struct hws_cpu_buffer *cb = this_cpu_ptr(&sampler_cpu_buffer); if (!(param32 & CPU_MF_INT_SF_MASK)) return; -- GitLab From 0bf7fcf155160fd483af7ffdc50efd4be96f1c96 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:46 -0500 Subject: [PATCH 0664/5088] s390: cio driver &__get_cpu_var replacements Use this_cpu_ptr() instead of &__get_cpu_var() Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/s390/cio/ccwreq.c | 2 +- drivers/s390/cio/chsc_sch.c | 2 +- drivers/s390/cio/cio.c | 6 +++--- drivers/s390/cio/device_fsm.c | 4 ++-- drivers/s390/cio/eadm_sch.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c index 07676c22d514..79f59915f71b 100644 --- a/drivers/s390/cio/ccwreq.c +++ b/drivers/s390/cio/ccwreq.c @@ -252,7 +252,7 @@ static void ccwreq_log_status(struct ccw_device *cdev, enum io_status status) */ void ccw_request_handler(struct ccw_device *cdev) { - struct irb *irb = &__get_cpu_var(cio_irb); + struct irb *irb = this_cpu_ptr(&cio_irb); struct ccw_request *req = &cdev->private->req; enum io_status status; int rc = -EOPNOTSUPP; diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 3d22d2a4ce14..213159dec89e 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -58,7 +58,7 @@ static void chsc_subchannel_irq(struct subchannel *sch) { struct chsc_private *private = dev_get_drvdata(&sch->dev); struct chsc_request *request = private->request; - struct irb *irb = &__get_cpu_var(cio_irb); + struct irb *irb = this_cpu_ptr(&cio_irb); CHSC_LOG(4, "irb"); CHSC_LOG_HEX(4, irb, sizeof(*irb)); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 2905d8b0ec95..dacdaaa44919 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -563,7 +563,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy) __this_cpu_write(s390_idle.nohz_delay, 1); tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; - irb = &__get_cpu_var(cio_irb); + irb = this_cpu_ptr(&cio_irb); sch = (struct subchannel *)(unsigned long) tpi_info->intparm; if (!sch) { /* Clear pending interrupt condition. */ @@ -613,7 +613,7 @@ void cio_tsch(struct subchannel *sch) struct irb *irb; int irq_context; - irb = &__get_cpu_var(cio_irb); + irb = this_cpu_ptr(&cio_irb); /* Store interrupt response block to lowcore. */ if (tsch(sch->schid, irb) != 0) /* Not status pending or not operational. */ @@ -751,7 +751,7 @@ __clear_io_subchannel_easy(struct subchannel_id schid) struct tpi_info ti; if (tpi(&ti)) { - tsch(ti.schid, &__get_cpu_var(cio_irb)); + tsch(ti.schid, this_cpu_ptr(&cio_irb)); if (schid_equal(&ti.schid, &schid)) return 0; } diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 0bc902b3cd84..83da53c8e54c 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -739,7 +739,7 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) struct irb *irb; int is_cmd; - irb = &__get_cpu_var(cio_irb); + irb = this_cpu_ptr(&cio_irb); is_cmd = !scsw_is_tm(&irb->scsw); /* Check for unsolicited interrupt. */ if (!scsw_is_solicited(&irb->scsw)) { @@ -805,7 +805,7 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) { struct irb *irb; - irb = &__get_cpu_var(cio_irb); + irb = this_cpu_ptr(&cio_irb); /* Check for unsolicited interrupt. */ if (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index c4f7bf3e24c2..37f0834300ea 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c @@ -134,7 +134,7 @@ static void eadm_subchannel_irq(struct subchannel *sch) { struct eadm_private *private = get_eadm_private(sch); struct eadm_scsw *scsw = &sch->schib.scsw.eadm; - struct irb *irb = &__get_cpu_var(cio_irb); + struct irb *irb = this_cpu_ptr(&cio_irb); int error = 0; EADM_LOG(6, "irq"); -- GitLab From 6065a244a039a23d933e4b803a4e052da2849208 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:47 -0500 Subject: [PATCH 0665/5088] ia64: Replace __get_cpu_var uses __get_cpu_var() is used for multiple purposes in the kernel source. One of them is address calculation via the form &__get_cpu_var(x). This calculates the address for the instance of the percpu variable of the current processor based on an offset. Other use cases are for storing and retrieving data from the current processors percpu area. __get_cpu_var() can be used as an lvalue when writing data or on the right side of an assignment. __get_cpu_var() is defined as : #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) __get_cpu_var() always only does an address determination. However, store and retrieve operations could use a segment prefix (or global register on other platforms) to avoid the address calculation. this_cpu_write() and this_cpu_read() can directly take an offset into a percpu area and use optimized assembly code to read and write per cpu variables. This patch converts __get_cpu_var into either an explicit address calculation using this_cpu_ptr() or into a use of this_cpu operations that use the offset. Thereby address calculations are avoided and less registers are used when code is generated. At the end of the patch set all uses of __get_cpu_var have been removed so the macro is removed too. The patch set includes passes over all arches as well. Once these operations are used throughout then specialized macros can be defined in non -x86 arches as well in order to optimize per cpu access by f.e. using a global register that may be set to the per cpu base. Transformations done to __get_cpu_var() 1. Determine the address of the percpu instance of the current processor. DEFINE_PER_CPU(int, y); int *x = &__get_cpu_var(y); Converts to int *x = this_cpu_ptr(&y); 2. Same as #1 but this time an array structure is involved. DEFINE_PER_CPU(int, y[20]); int *x = __get_cpu_var(y); Converts to int *x = this_cpu_ptr(y); 3. Retrieve the content of the current processors instance of a per cpu variable. DEFINE_PER_CPU(int, y); int x = __get_cpu_var(y) Converts to int x = __this_cpu_read(y); 4. Retrieve the content of a percpu struct DEFINE_PER_CPU(struct mystruct, y); struct mystruct x = __get_cpu_var(y); Converts to memcpy(&x, this_cpu_ptr(&y), sizeof(x)); 5. Assignment to a per cpu variable DEFINE_PER_CPU(int, y) __get_cpu_var(y) = x; Converts to __this_cpu_write(y, x); 6. Increment/Decrement etc of a per cpu variable DEFINE_PER_CPU(int, y); __get_cpu_var(y)++ Converts to __this_cpu_inc(y) Cc: Tony Luck Cc: Fenghua Yu Cc: linux-ia64@vger.kernel.org Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/ia64/include/asm/hw_irq.h | 2 +- arch/ia64/include/asm/sn/arch.h | 4 ++-- arch/ia64/include/asm/sn/nodepda.h | 2 +- arch/ia64/include/asm/switch_to.h | 2 +- arch/ia64/include/asm/uv/uv_hub.h | 2 +- arch/ia64/kernel/irq.c | 2 +- arch/ia64/kernel/irq_ia64.c | 4 ++-- arch/ia64/kernel/kprobes.c | 6 +++--- arch/ia64/kernel/mca.c | 16 ++++++++-------- arch/ia64/kernel/process.c | 6 +++--- arch/ia64/kernel/traps.c | 2 +- arch/ia64/sn/kernel/sn2/sn2_smp.c | 28 ++++++++++++++-------------- 12 files changed, 38 insertions(+), 38 deletions(-) diff --git a/arch/ia64/include/asm/hw_irq.h b/arch/ia64/include/asm/hw_irq.h index 029bab36cd91..668786e84af8 100644 --- a/arch/ia64/include/asm/hw_irq.h +++ b/arch/ia64/include/asm/hw_irq.h @@ -159,7 +159,7 @@ static inline ia64_vector __ia64_irq_to_vector(int irq) static inline unsigned int __ia64_local_vector_to_irq (ia64_vector vec) { - return __get_cpu_var(vector_irq)[vec]; + return __this_cpu_read(vector_irq[vec]); } #endif diff --git a/arch/ia64/include/asm/sn/arch.h b/arch/ia64/include/asm/sn/arch.h index 7caa1f44cd95..31eb784866f8 100644 --- a/arch/ia64/include/asm/sn/arch.h +++ b/arch/ia64/include/asm/sn/arch.h @@ -57,7 +57,7 @@ struct sn_hub_info_s { u16 nasid_bitmask; }; DECLARE_PER_CPU(struct sn_hub_info_s, __sn_hub_info); -#define sn_hub_info (&__get_cpu_var(__sn_hub_info)) +#define sn_hub_info this_cpu_ptr(&__sn_hub_info) #define is_shub2() (sn_hub_info->shub2) #define is_shub1() (sn_hub_info->shub2 == 0) @@ -72,7 +72,7 @@ DECLARE_PER_CPU(struct sn_hub_info_s, __sn_hub_info); * cpu. */ DECLARE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]); -#define sn_cnodeid_to_nasid (&__get_cpu_var(__sn_cnodeid_to_nasid[0])) +#define sn_cnodeid_to_nasid this_cpu_ptr(&__sn_cnodeid_to_nasid[0]) extern u8 sn_partition_id; diff --git a/arch/ia64/include/asm/sn/nodepda.h b/arch/ia64/include/asm/sn/nodepda.h index ee118b901de4..7c8b4710f071 100644 --- a/arch/ia64/include/asm/sn/nodepda.h +++ b/arch/ia64/include/asm/sn/nodepda.h @@ -70,7 +70,7 @@ typedef struct nodepda_s nodepda_t; */ DECLARE_PER_CPU(struct nodepda_s *, __sn_nodepda); -#define sn_nodepda (__get_cpu_var(__sn_nodepda)) +#define sn_nodepda __this_cpu_read(__sn_nodepda) #define NODEPDA(cnodeid) (sn_nodepda->pernode_pdaindr[cnodeid]) /* diff --git a/arch/ia64/include/asm/switch_to.h b/arch/ia64/include/asm/switch_to.h index d38c7ea5eea5..e8f3585e7e7a 100644 --- a/arch/ia64/include/asm/switch_to.h +++ b/arch/ia64/include/asm/switch_to.h @@ -32,7 +32,7 @@ extern void ia64_load_extra (struct task_struct *task); #ifdef CONFIG_PERFMON DECLARE_PER_CPU(unsigned long, pfm_syst_info); -# define PERFMON_IS_SYSWIDE() (__get_cpu_var(pfm_syst_info) & 0x1) +# define PERFMON_IS_SYSWIDE() (__this_cpu_read(pfm_syst_info) & 0x1) #else # define PERFMON_IS_SYSWIDE() (0) #endif diff --git a/arch/ia64/include/asm/uv/uv_hub.h b/arch/ia64/include/asm/uv/uv_hub.h index 53e9dfacd073..2a88c7204e52 100644 --- a/arch/ia64/include/asm/uv/uv_hub.h +++ b/arch/ia64/include/asm/uv/uv_hub.h @@ -108,7 +108,7 @@ struct uv_hub_info_s { unsigned char n_val; }; DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); -#define uv_hub_info (&__get_cpu_var(__uv_hub_info)) +#define uv_hub_info this_cpu_ptr(&__uv_hub_info) #define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu)) /* diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index f2c418281130..812a1e6b3179 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -42,7 +42,7 @@ ia64_vector __ia64_irq_to_vector(int irq) unsigned int __ia64_local_vector_to_irq (ia64_vector vec) { - return __get_cpu_var(vector_irq)[vec]; + return __this_cpu_read(vector_irq[vec]); } #endif diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 03ea78ed64a9..698d8fefde6c 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -330,7 +330,7 @@ static irqreturn_t smp_irq_move_cleanup_interrupt(int irq, void *dev_id) int irq; struct irq_desc *desc; struct irq_cfg *cfg; - irq = __get_cpu_var(vector_irq)[vector]; + irq = __this_cpu_read(vector_irq[vector]); if (irq < 0) continue; @@ -344,7 +344,7 @@ static irqreturn_t smp_irq_move_cleanup_interrupt(int irq, void *dev_id) goto unlock; spin_lock_irqsave(&vector_lock, flags); - __get_cpu_var(vector_irq)[vector] = -1; + __this_cpu_write(vector_irq[vector], -1); cpu_clear(me, vector_table[vector]); spin_unlock_irqrestore(&vector_lock, flags); cfg->move_cleanup_count--; diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 074fde49c9e6..c7c51445c3be 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c @@ -396,7 +396,7 @@ static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) { unsigned int i; i = atomic_read(&kcb->prev_kprobe_index); - __get_cpu_var(current_kprobe) = kcb->prev_kprobe[i-1].kp; + __this_cpu_write(current_kprobe, kcb->prev_kprobe[i-1].kp); kcb->kprobe_status = kcb->prev_kprobe[i-1].status; atomic_sub(1, &kcb->prev_kprobe_index); } @@ -404,7 +404,7 @@ static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) static void __kprobes set_current_kprobe(struct kprobe *p, struct kprobe_ctlblk *kcb) { - __get_cpu_var(current_kprobe) = p; + __this_cpu_write(current_kprobe, p); } static void kretprobe_trampoline(void) @@ -823,7 +823,7 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) /* * jprobe instrumented function just completed */ - p = __get_cpu_var(current_kprobe); + p = __this_cpu_read(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) { goto ss_probe; } diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index db7b36bb068b..8bfd36af46f8 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -1341,7 +1341,7 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, ia64_mlogbuf_finish(1); } - if (__get_cpu_var(ia64_mca_tr_reload)) { + if (__this_cpu_read(ia64_mca_tr_reload)) { mca_insert_tr(0x1); /*Reload dynamic itrs*/ mca_insert_tr(0x2); /*Reload dynamic itrs*/ } @@ -1868,14 +1868,14 @@ ia64_mca_cpu_init(void *cpu_data) "MCA", cpu); format_mca_init_stack(data, offsetof(struct ia64_mca_cpu, init_stack), "INIT", cpu); - __get_cpu_var(ia64_mca_data) = __per_cpu_mca[cpu] = __pa(data); + __this_cpu_write(ia64_mca_data, (__per_cpu_mca[cpu] = __pa(data))); /* * Stash away a copy of the PTE needed to map the per-CPU page. * We may need it during MCA recovery. */ - __get_cpu_var(ia64_mca_per_cpu_pte) = - pte_val(mk_pte_phys(__pa(cpu_data), PAGE_KERNEL)); + __this_cpu_write(ia64_mca_per_cpu_pte, + pte_val(mk_pte_phys(__pa(cpu_data), PAGE_KERNEL))); /* * Also, stash away a copy of the PAL address and the PTE @@ -1884,10 +1884,10 @@ ia64_mca_cpu_init(void *cpu_data) pal_vaddr = efi_get_pal_addr(); if (!pal_vaddr) return; - __get_cpu_var(ia64_mca_pal_base) = - GRANULEROUNDDOWN((unsigned long) pal_vaddr); - __get_cpu_var(ia64_mca_pal_pte) = pte_val(mk_pte_phys(__pa(pal_vaddr), - PAGE_KERNEL)); + __this_cpu_write(ia64_mca_pal_base, + GRANULEROUNDDOWN((unsigned long) pal_vaddr)); + __this_cpu_write(ia64_mca_pal_pte, pte_val(mk_pte_phys(__pa(pal_vaddr), + PAGE_KERNEL))); } static void ia64_mca_cmc_vector_adjust(void *dummy) diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index deed6fa96bb0..b51514957620 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -215,7 +215,7 @@ static inline void play_dead(void) unsigned int this_cpu = smp_processor_id(); /* Ack it */ - __get_cpu_var(cpu_state) = CPU_DEAD; + __this_cpu_write(cpu_state, CPU_DEAD); max_xtp(); local_irq_disable(); @@ -273,7 +273,7 @@ ia64_save_extra (struct task_struct *task) if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) pfm_save_regs(task); - info = __get_cpu_var(pfm_syst_info); + info = __this_cpu_read(pfm_syst_info); if (info & PFM_CPUINFO_SYST_WIDE) pfm_syst_wide_update_task(task, info, 0); #endif @@ -293,7 +293,7 @@ ia64_load_extra (struct task_struct *task) if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) pfm_load_regs(task); - info = __get_cpu_var(pfm_syst_info); + info = __this_cpu_read(pfm_syst_info); if (info & PFM_CPUINFO_SYST_WIDE) pfm_syst_wide_update_task(task, info, 1); #endif diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index d3636e67a98e..6f7d4a4dcf24 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -299,7 +299,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) if (!(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { unsigned long count, current_jiffies = jiffies; - struct fpu_swa_msg *cp = &__get_cpu_var(cpulast); + struct fpu_swa_msg *cp = this_cpu_ptr(&cpulast); if (unlikely(current_jiffies > cp->time)) cp->count = 0; diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c index 68c845411624..f9c8d9fc5939 100644 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c @@ -134,8 +134,8 @@ sn2_ipi_flush_all_tlb(struct mm_struct *mm) itc = ia64_get_itc(); smp_flush_tlb_cpumask(*mm_cpumask(mm)); itc = ia64_get_itc() - itc; - __get_cpu_var(ptcstats).shub_ipi_flushes_itc_clocks += itc; - __get_cpu_var(ptcstats).shub_ipi_flushes++; + __this_cpu_add(ptcstats.shub_ipi_flushes_itc_clocks, itc); + __this_cpu_inc(ptcstats.shub_ipi_flushes); } /** @@ -199,14 +199,14 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start, start += (1UL << nbits); } while (start < end); ia64_srlz_i(); - __get_cpu_var(ptcstats).ptc_l++; + __this_cpu_inc(ptcstats.ptc_l); preempt_enable(); return; } if (atomic_read(&mm->mm_users) == 1 && mymm) { flush_tlb_mm(mm); - __get_cpu_var(ptcstats).change_rid++; + __this_cpu_inc(ptcstats.change_rid); preempt_enable(); return; } @@ -250,11 +250,11 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start, spin_lock_irqsave(PTC_LOCK(shub1), flags); itc2 = ia64_get_itc(); - __get_cpu_var(ptcstats).lock_itc_clocks += itc2 - itc; - __get_cpu_var(ptcstats).shub_ptc_flushes++; - __get_cpu_var(ptcstats).nodes_flushed += nix; + __this_cpu_add(ptcstats.lock_itc_clocks, itc2 - itc); + __this_cpu_inc(ptcstats.shub_ptc_flushes); + __this_cpu_add(ptcstats.nodes_flushed, nix); if (!mymm) - __get_cpu_var(ptcstats).shub_ptc_flushes_not_my_mm++; + __this_cpu_inc(ptcstats.shub_ptc_flushes_not_my_mm); if (use_cpu_ptcga && !mymm) { old_rr = ia64_get_rr(start); @@ -299,9 +299,9 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start, done: itc2 = ia64_get_itc() - itc2; - __get_cpu_var(ptcstats).shub_itc_clocks += itc2; - if (itc2 > __get_cpu_var(ptcstats).shub_itc_clocks_max) - __get_cpu_var(ptcstats).shub_itc_clocks_max = itc2; + __this_cpu_add(ptcstats.shub_itc_clocks, itc2); + if (itc2 > __this_cpu_read(ptcstats.shub_itc_clocks_max)) + __this_cpu_write(ptcstats.shub_itc_clocks_max, itc2); if (old_rr) { ia64_set_rr(start, old_rr); @@ -311,7 +311,7 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start, spin_unlock_irqrestore(PTC_LOCK(shub1), flags); if (flush_opt == 1 && deadlock) { - __get_cpu_var(ptcstats).deadlocks++; + __this_cpu_inc(ptcstats.deadlocks); sn2_ipi_flush_all_tlb(mm); } @@ -334,7 +334,7 @@ sn2_ptc_deadlock_recovery(short *nasids, short ib, short ie, int mynasid, short nasid, i; unsigned long *piows, zeroval, n; - __get_cpu_var(ptcstats).deadlocks++; + __this_cpu_inc(ptcstats.deadlocks); piows = (unsigned long *) pda->pio_write_status_addr; zeroval = pda->pio_write_status_val; @@ -349,7 +349,7 @@ sn2_ptc_deadlock_recovery(short *nasids, short ib, short ie, int mynasid, ptc1 = CHANGE_NASID(nasid, ptc1); n = sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows, zeroval); - __get_cpu_var(ptcstats).deadlocks2 += n; + __this_cpu_add(ptcstats.deadlocks2, n); } } -- GitLab From 2999a4b354c24985268f9310bc9522ff358453a8 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:48 -0500 Subject: [PATCH 0666/5088] alpha: Replace __get_cpu_var __get_cpu_var() is used for multiple purposes in the kernel source. One of them is address calculation via the form &__get_cpu_var(x). This calculates the address for the instance of the percpu variable of the current processor based on an offset. Other use cases are for storing and retrieving data from the current processors percpu area. __get_cpu_var() can be used as an lvalue when writing data or on the right side of an assignment. __get_cpu_var() is defined as : #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) __get_cpu_var() always only does an address determination. However, store and retrieve operations could use a segment prefix (or global register on other platforms) to avoid the address calculation. this_cpu_write() and this_cpu_read() can directly take an offset into a percpu area and use optimized assembly code to read and write per cpu variables. This patch converts __get_cpu_var into either an explicit address calculation using this_cpu_ptr() or into a use of this_cpu operations that use the offset. Thereby address calculations are avoided and less registers are used when code is generated. At the end of the patch set all uses of __get_cpu_var have been removed so the macro is removed too. The patch set includes passes over all arches as well. Once these operations are used throughout then specialized macros can be defined in non -x86 arches as well in order to optimize per cpu access by f.e. using a global register that may be set to the per cpu base. Transformations done to __get_cpu_var() 1. Determine the address of the percpu instance of the current processor. DEFINE_PER_CPU(int, y); int *x = &__get_cpu_var(y); Converts to int *x = this_cpu_ptr(&y); 2. Same as #1 but this time an array structure is involved. DEFINE_PER_CPU(int, y[20]); int *x = __get_cpu_var(y); Converts to int *x = this_cpu_ptr(y); 3. Retrieve the content of the current processors instance of a per cpu variable. DEFINE_PER_CPU(int, y); int x = __get_cpu_var(y) Converts to int x = __this_cpu_read(y); 4. Retrieve the content of a percpu struct DEFINE_PER_CPU(struct mystruct, y); struct mystruct x = __get_cpu_var(y); Converts to memcpy(&x, this_cpu_ptr(&y), sizeof(x)); 5. Assignment to a per cpu variable DEFINE_PER_CPU(int, y) __get_cpu_var(y) = x; Converts to __this_cpu_write(y, x); 6. Increment/Decrement etc of a per cpu variable DEFINE_PER_CPU(int, y); __get_cpu_var(y)++ Converts to __this_cpu_inc(y) CC: Ivan Kokshaysky Cc: Matt Turner Acked-by: Richard Henderson Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/alpha/kernel/perf_event.c | 16 ++++++++-------- arch/alpha/kernel/time.c | 6 +++--- arch/powerpc/include/asm/cputime.h | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c index c52e7f0ee5f6..5c218aa3f3df 100644 --- a/arch/alpha/kernel/perf_event.c +++ b/arch/alpha/kernel/perf_event.c @@ -431,7 +431,7 @@ static void maybe_change_configuration(struct cpu_hw_events *cpuc) */ static int alpha_pmu_add(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; int n0; int ret; @@ -483,7 +483,7 @@ static int alpha_pmu_add(struct perf_event *event, int flags) */ static void alpha_pmu_del(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; unsigned long irq_flags; int j; @@ -531,7 +531,7 @@ static void alpha_pmu_read(struct perf_event *event) static void alpha_pmu_stop(struct perf_event *event, int flags) { struct hw_perf_event *hwc = &event->hw; - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (!(hwc->state & PERF_HES_STOPPED)) { cpuc->idx_mask &= ~(1UL<idx); @@ -551,7 +551,7 @@ static void alpha_pmu_stop(struct perf_event *event, int flags) static void alpha_pmu_start(struct perf_event *event, int flags) { struct hw_perf_event *hwc = &event->hw; - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED))) return; @@ -724,7 +724,7 @@ static int alpha_pmu_event_init(struct perf_event *event) */ static void alpha_pmu_enable(struct pmu *pmu) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (cpuc->enabled) return; @@ -750,7 +750,7 @@ static void alpha_pmu_enable(struct pmu *pmu) static void alpha_pmu_disable(struct pmu *pmu) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); if (!cpuc->enabled) return; @@ -814,8 +814,8 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr, struct hw_perf_event *hwc; int idx, j; - __get_cpu_var(irq_pmi_count)++; - cpuc = &__get_cpu_var(cpu_hw_events); + __this_cpu_inc(irq_pmi_count); + cpuc = this_cpu_ptr(&cpu_hw_events); /* Completely counting through the PMC's period to trigger a new PMC * overflow interrupt while in this interrupt routine is utterly diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index ee39cee8064c..643a9dcdf093 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -56,9 +56,9 @@ unsigned long est_cycle_freq; DEFINE_PER_CPU(u8, irq_work_pending); -#define set_irq_work_pending_flag() __get_cpu_var(irq_work_pending) = 1 -#define test_irq_work_pending() __get_cpu_var(irq_work_pending) -#define clear_irq_work_pending() __get_cpu_var(irq_work_pending) = 0 +#define set_irq_work_pending_flag() __this_cpu_write(irq_work_pending, 1) +#define test_irq_work_pending() __this_cpu_read(irq_work_pending) +#define clear_irq_work_pending() __this_cpu_write(irq_work_pending, 0) void arch_irq_work_raise(void) { diff --git a/arch/powerpc/include/asm/cputime.h b/arch/powerpc/include/asm/cputime.h index 607559ab271f..e5d10ab8463b 100644 --- a/arch/powerpc/include/asm/cputime.h +++ b/arch/powerpc/include/asm/cputime.h @@ -56,10 +56,10 @@ static inline unsigned long cputime_to_jiffies(const cputime_t ct) static inline cputime_t cputime_to_scaled(const cputime_t ct) { if (cpu_has_feature(CPU_FTR_SPURR) && - __get_cpu_var(cputime_last_delta)) + __this_cpu_read(cputime_last_delta)) return (__force u64) ct * - __get_cpu_var(cputime_scaled_last_delta) / - __get_cpu_var(cputime_last_delta); + __this_cpu_read(cputime_scaled_last_delta) / + __this_cpu_read(cputime_last_delta); return ct; } -- GitLab From 5828f666c069af74e00db21559f1535103c9f79a Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:49 -0500 Subject: [PATCH 0667/5088] powerpc: Replace __get_cpu_var uses __get_cpu_var() is used for multiple purposes in the kernel source. One of them is address calculation via the form &__get_cpu_var(x). This calculates the address for the instance of the percpu variable of the current processor based on an offset. Other use cases are for storing and retrieving data from the current processors percpu area. __get_cpu_var() can be used as an lvalue when writing data or on the right side of an assignment. __get_cpu_var() is defined as : #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) __get_cpu_var() always only does an address determination. However, store and retrieve operations could use a segment prefix (or global register on other platforms) to avoid the address calculation. this_cpu_write() and this_cpu_read() can directly take an offset into a percpu area and use optimized assembly code to read and write per cpu variables. This patch converts __get_cpu_var into either an explicit address calculation using this_cpu_ptr() or into a use of this_cpu operations that use the offset. Thereby address calculations are avoided and less registers are used when code is generated. At the end of the patch set all uses of __get_cpu_var have been removed so the macro is removed too. The patch set includes passes over all arches as well. Once these operations are used throughout then specialized macros can be defined in non -x86 arches as well in order to optimize per cpu access by f.e. using a global register that may be set to the per cpu base. Transformations done to __get_cpu_var() 1. Determine the address of the percpu instance of the current processor. DEFINE_PER_CPU(int, y); int *x = &__get_cpu_var(y); Converts to int *x = this_cpu_ptr(&y); 2. Same as #1 but this time an array structure is involved. DEFINE_PER_CPU(int, y[20]); int *x = __get_cpu_var(y); Converts to int *x = this_cpu_ptr(y); 3. Retrieve the content of the current processors instance of a per cpu variable. DEFINE_PER_CPU(int, y); int x = __get_cpu_var(y) Converts to int x = __this_cpu_read(y); 4. Retrieve the content of a percpu struct DEFINE_PER_CPU(struct mystruct, y); struct mystruct x = __get_cpu_var(y); Converts to memcpy(&x, this_cpu_ptr(&y), sizeof(x)); 5. Assignment to a per cpu variable DEFINE_PER_CPU(int, y) __get_cpu_var(y) = x; Converts to __this_cpu_write(y, x); 6. Increment/Decrement etc of a per cpu variable DEFINE_PER_CPU(int, y); __get_cpu_var(y)++ Converts to __this_cpu_inc(y) tj: Folded a fix patch. http://lkml.kernel.org/g/alpine.DEB.2.11.1408172143020.9652@gentwo.org Cc: Benjamin Herrenschmidt CC: Paul Mackerras Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/powerpc/include/asm/hardirq.h | 4 +++- arch/powerpc/include/asm/tlbflush.h | 4 ++-- arch/powerpc/include/asm/xics.h | 8 +++---- arch/powerpc/kernel/dbell.c | 2 +- arch/powerpc/kernel/hw_breakpoint.c | 6 ++--- arch/powerpc/kernel/iommu.c | 2 +- arch/powerpc/kernel/irq.c | 4 ++-- arch/powerpc/kernel/kgdb.c | 2 +- arch/powerpc/kernel/kprobes.c | 6 ++--- arch/powerpc/kernel/mce.c | 24 +++++++++---------- arch/powerpc/kernel/process.c | 10 ++++---- arch/powerpc/kernel/smp.c | 6 ++--- arch/powerpc/kernel/sysfs.c | 4 ++-- arch/powerpc/kernel/time.c | 22 ++++++++--------- arch/powerpc/kernel/traps.c | 8 +++---- arch/powerpc/kvm/e500.c | 14 +++++------ arch/powerpc/kvm/e500mc.c | 4 ++-- arch/powerpc/mm/hash_native_64.c | 2 +- arch/powerpc/mm/hash_utils_64.c | 2 +- arch/powerpc/mm/hugetlbpage-book3e.c | 6 ++--- arch/powerpc/mm/hugetlbpage.c | 2 +- arch/powerpc/perf/core-book3s.c | 22 ++++++++--------- arch/powerpc/perf/core-fsl-emb.c | 6 ++--- arch/powerpc/platforms/cell/interrupt.c | 6 ++--- .../platforms/powernv/opal-tracepoints.c | 4 ++-- arch/powerpc/platforms/ps3/interrupt.c | 2 +- arch/powerpc/platforms/pseries/dtl.c | 2 +- arch/powerpc/platforms/pseries/hvCall_inst.c | 4 ++-- arch/powerpc/platforms/pseries/iommu.c | 8 +++---- arch/powerpc/platforms/pseries/lpar.c | 6 ++--- arch/powerpc/platforms/pseries/ras.c | 4 ++-- arch/powerpc/sysdev/xics/xics-common.c | 2 +- 32 files changed, 105 insertions(+), 103 deletions(-) diff --git a/arch/powerpc/include/asm/hardirq.h b/arch/powerpc/include/asm/hardirq.h index 1bbb3013d6aa..8d907ba4fd05 100644 --- a/arch/powerpc/include/asm/hardirq.h +++ b/arch/powerpc/include/asm/hardirq.h @@ -21,7 +21,9 @@ DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); #define __ARCH_IRQ_STAT -#define local_softirq_pending() __get_cpu_var(irq_stat).__softirq_pending +#define local_softirq_pending() __this_cpu_read(irq_stat.__softirq_pending) +#define set_softirq_pending(x) __this_cpu_write(irq_stat._softirq_pending, (x)) +#define or_softirq_pending(x) __this_cpu_or(irq_stat._softirq_pending, (x)) static inline void ack_bad_irq(unsigned int irq) { diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index 2def01ed0cb2..cd7c2719d3ef 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -107,14 +107,14 @@ extern void __flush_tlb_pending(struct ppc64_tlb_batch *batch); static inline void arch_enter_lazy_mmu_mode(void) { - struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); batch->active = 1; } static inline void arch_leave_lazy_mmu_mode(void) { - struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); if (batch->index) __flush_tlb_pending(batch); diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index 282d43a0c855..5007ad0448ce 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h @@ -97,7 +97,7 @@ DECLARE_PER_CPU(struct xics_cppr, xics_cppr); static inline void xics_push_cppr(unsigned int vec) { - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1)) return; @@ -110,7 +110,7 @@ static inline void xics_push_cppr(unsigned int vec) static inline unsigned char xics_pop_cppr(void) { - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); if (WARN_ON(os_cppr->index < 1)) return LOWEST_PRIORITY; @@ -120,7 +120,7 @@ static inline unsigned char xics_pop_cppr(void) static inline void xics_set_base_cppr(unsigned char cppr) { - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); /* we only really want to set the priority when there's * just one cppr value on the stack @@ -132,7 +132,7 @@ static inline void xics_set_base_cppr(unsigned char cppr) static inline unsigned char xics_cppr_top(void) { - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); return os_cppr->stack[os_cppr->index]; } diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index d55c76c571f3..f4217819cc31 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -41,7 +41,7 @@ void doorbell_exception(struct pt_regs *regs) may_hard_irq_enable(); - __get_cpu_var(irq_stat).doorbell_irqs++; + __this_cpu_inc(irq_stat.doorbell_irqs); smp_ipi_demux(); diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 0bb5918faaaf..b62f90eaf19e 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -63,7 +63,7 @@ int hw_breakpoint_slots(int type) int arch_install_hw_breakpoint(struct perf_event *bp) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); - struct perf_event **slot = &__get_cpu_var(bp_per_reg); + struct perf_event **slot = this_cpu_ptr(&bp_per_reg); *slot = bp; @@ -88,7 +88,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp) */ void arch_uninstall_hw_breakpoint(struct perf_event *bp) { - struct perf_event **slot = &__get_cpu_var(bp_per_reg); + struct perf_event **slot = this_cpu_ptr(&bp_per_reg); if (*slot != bp) { WARN_ONCE(1, "Can't find the breakpoint"); @@ -226,7 +226,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) */ rcu_read_lock(); - bp = __get_cpu_var(bp_per_reg); + bp = __this_cpu_read(bp_per_reg); if (!bp) goto out; info = counter_arch_bp(bp); diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index a10642a0d861..71e60bfb89e2 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -208,7 +208,7 @@ static unsigned long iommu_range_alloc(struct device *dev, * We don't need to disable preemption here because any CPU can * safely use any IOMMU pool. */ - pool_nr = __raw_get_cpu_var(iommu_pool_hash) & (tbl->nr_pools - 1); + pool_nr = __this_cpu_read(iommu_pool_hash) & (tbl->nr_pools - 1); if (largealloc) pool = &(tbl->large_pool); diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 4c5891de162e..74d40c6855b8 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -114,7 +114,7 @@ static inline notrace void set_soft_enabled(unsigned long enable) static inline notrace int decrementer_check_overflow(void) { u64 now = get_tb_or_rtc(); - u64 *next_tb = &__get_cpu_var(decrementers_next_tb); + u64 *next_tb = this_cpu_ptr(&decrementers_next_tb); return now >= *next_tb; } @@ -499,7 +499,7 @@ void __do_irq(struct pt_regs *regs) /* And finally process it */ if (unlikely(irq == NO_IRQ)) - __get_cpu_var(irq_stat).spurious_irqs++; + __this_cpu_inc(irq_stat.spurious_irqs); else generic_handle_irq(irq); diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 8504657379f1..e77c3ccf8dcf 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -155,7 +155,7 @@ static int kgdb_singlestep(struct pt_regs *regs) { struct thread_info *thread_info, *exception_thread_info; struct thread_info *backup_current_thread_info = - &__get_cpu_var(kgdb_thread_info); + this_cpu_ptr(&kgdb_thread_info); if (user_mode(regs)) return 0; diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 2f72af82513c..7c053f281406 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -119,7 +119,7 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) { - __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); kcb->kprobe_status = kcb->prev_kprobe.status; kcb->kprobe_saved_msr = kcb->prev_kprobe.saved_msr; } @@ -127,7 +127,7 @@ static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { - __get_cpu_var(current_kprobe) = p; + __this_cpu_write(current_kprobe, p); kcb->kprobe_saved_msr = regs->msr; } @@ -192,7 +192,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) ret = 1; goto no_kprobe; } - p = __get_cpu_var(current_kprobe); + p = __this_cpu_read(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) { goto ss_probe; } diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c index a7fd4cb78b78..15c99b649b04 100644 --- a/arch/powerpc/kernel/mce.c +++ b/arch/powerpc/kernel/mce.c @@ -73,8 +73,8 @@ void save_mce_event(struct pt_regs *regs, long handled, uint64_t nip, uint64_t addr) { uint64_t srr1; - int index = __get_cpu_var(mce_nest_count)++; - struct machine_check_event *mce = &__get_cpu_var(mce_event[index]); + int index = __this_cpu_inc_return(mce_nest_count); + struct machine_check_event *mce = this_cpu_ptr(&mce_event[index]); /* * Return if we don't have enough space to log mce event. @@ -143,7 +143,7 @@ void save_mce_event(struct pt_regs *regs, long handled, */ int get_mce_event(struct machine_check_event *mce, bool release) { - int index = __get_cpu_var(mce_nest_count) - 1; + int index = __this_cpu_read(mce_nest_count) - 1; struct machine_check_event *mc_evt; int ret = 0; @@ -153,7 +153,7 @@ int get_mce_event(struct machine_check_event *mce, bool release) /* Check if we have MCE info to process. */ if (index < MAX_MC_EVT) { - mc_evt = &__get_cpu_var(mce_event[index]); + mc_evt = this_cpu_ptr(&mce_event[index]); /* Copy the event structure and release the original */ if (mce) *mce = *mc_evt; @@ -163,7 +163,7 @@ int get_mce_event(struct machine_check_event *mce, bool release) } /* Decrement the count to free the slot. */ if (release) - __get_cpu_var(mce_nest_count)--; + __this_cpu_dec(mce_nest_count); return ret; } @@ -184,13 +184,13 @@ void machine_check_queue_event(void) if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) return; - index = __get_cpu_var(mce_queue_count)++; + index = __this_cpu_inc_return(mce_queue_count); /* If queue is full, just return for now. */ if (index >= MAX_MC_EVT) { - __get_cpu_var(mce_queue_count)--; + __this_cpu_dec(mce_queue_count); return; } - __get_cpu_var(mce_event_queue[index]) = evt; + memcpy(this_cpu_ptr(&mce_event_queue[index]), &evt, sizeof(evt)); /* Queue irq work to process this event later. */ irq_work_queue(&mce_event_process_work); @@ -208,11 +208,11 @@ static void machine_check_process_queued_event(struct irq_work *work) * For now just print it to console. * TODO: log this error event to FSP or nvram. */ - while (__get_cpu_var(mce_queue_count) > 0) { - index = __get_cpu_var(mce_queue_count) - 1; + while (__this_cpu_read(mce_queue_count) > 0) { + index = __this_cpu_read(mce_queue_count) - 1; machine_check_print_event_info( - &__get_cpu_var(mce_event_queue[index])); - __get_cpu_var(mce_queue_count)--; + this_cpu_ptr(&mce_event_queue[index])); + __this_cpu_dec(mce_queue_count); } } diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index bf44ae962ab8..2df2f2956520 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -498,7 +498,7 @@ static inline int set_dawr(struct arch_hw_breakpoint *brk) void __set_breakpoint(struct arch_hw_breakpoint *brk) { - __get_cpu_var(current_brk) = *brk; + __this_cpu_write(current_brk, *brk); if (cpu_has_feature(CPU_FTR_DAWR)) set_dawr(brk); @@ -841,7 +841,7 @@ struct task_struct *__switch_to(struct task_struct *prev, * schedule DABR */ #ifndef CONFIG_HAVE_HW_BREAKPOINT - if (unlikely(!hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk))) + if (unlikely(!hw_brk_match(this_cpu_ptr(¤t_brk), &new->thread.hw_brk))) __set_breakpoint(&new->thread.hw_brk); #endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif @@ -855,7 +855,7 @@ struct task_struct *__switch_to(struct task_struct *prev, * Collect processor utilization data per process */ if (firmware_has_feature(FW_FEATURE_SPLPAR)) { - struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); + struct cpu_usage *cu = this_cpu_ptr(&cpu_usage_array); long unsigned start_tb, current_tb; start_tb = old_thread->start_tb; cu->current_tb = current_tb = mfspr(SPRN_PURR); @@ -865,7 +865,7 @@ struct task_struct *__switch_to(struct task_struct *prev, #endif /* CONFIG_PPC64 */ #ifdef CONFIG_PPC_BOOK3S_64 - batch = &__get_cpu_var(ppc64_tlb_batch); + batch = this_cpu_ptr(&ppc64_tlb_batch); if (batch->active) { current_thread_info()->local_flags |= _TLF_LAZY_MMU; if (batch->index) @@ -888,7 +888,7 @@ struct task_struct *__switch_to(struct task_struct *prev, #ifdef CONFIG_PPC_BOOK3S_64 if (current_thread_info()->local_flags & _TLF_LAZY_MMU) { current_thread_info()->local_flags &= ~_TLF_LAZY_MMU; - batch = &__get_cpu_var(ppc64_tlb_batch); + batch = this_cpu_ptr(&ppc64_tlb_batch); batch->active = 1; } #endif /* CONFIG_PPC_BOOK3S_64 */ diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index a0738af4aba6..60391a51467a 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -242,7 +242,7 @@ void smp_muxed_ipi_message_pass(int cpu, int msg) irqreturn_t smp_ipi_demux(void) { - struct cpu_messages *info = &__get_cpu_var(ipi_message); + struct cpu_messages *info = this_cpu_ptr(&ipi_message); unsigned int all; mb(); /* order any irq clear */ @@ -438,9 +438,9 @@ void generic_mach_cpu_die(void) idle_task_exit(); cpu = smp_processor_id(); printk(KERN_DEBUG "CPU%d offline\n", cpu); - __get_cpu_var(cpu_state) = CPU_DEAD; + __this_cpu_write(cpu_state, CPU_DEAD); smp_wmb(); - while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) + while (__this_cpu_read(cpu_state) != CPU_UP_PREPARE) cpu_relax(); } diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 67fd2fd2620a..fa1fd8a0c867 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -394,10 +394,10 @@ void ppc_enable_pmcs(void) ppc_set_pmu_inuse(1); /* Only need to enable them once */ - if (__get_cpu_var(pmcs_enabled)) + if (__this_cpu_read(pmcs_enabled)) return; - __get_cpu_var(pmcs_enabled) = 1; + __this_cpu_write(pmcs_enabled, 1); if (ppc_md.enable_pmcs) ppc_md.enable_pmcs(); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 368ab374d33c..4769e5b7f905 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -458,9 +458,9 @@ static inline void clear_irq_work_pending(void) DEFINE_PER_CPU(u8, irq_work_pending); -#define set_irq_work_pending_flag() __get_cpu_var(irq_work_pending) = 1 -#define test_irq_work_pending() __get_cpu_var(irq_work_pending) -#define clear_irq_work_pending() __get_cpu_var(irq_work_pending) = 0 +#define set_irq_work_pending_flag() __this_cpu_write(irq_work_pending, 1) +#define test_irq_work_pending() __this_cpu_read(irq_work_pending) +#define clear_irq_work_pending() __this_cpu_write(irq_work_pending, 0) #endif /* 32 vs 64 bit */ @@ -482,8 +482,8 @@ void arch_irq_work_raise(void) void __timer_interrupt(void) { struct pt_regs *regs = get_irq_regs(); - u64 *next_tb = &__get_cpu_var(decrementers_next_tb); - struct clock_event_device *evt = &__get_cpu_var(decrementers); + u64 *next_tb = this_cpu_ptr(&decrementers_next_tb); + struct clock_event_device *evt = this_cpu_ptr(&decrementers); u64 now; trace_timer_interrupt_entry(regs); @@ -498,7 +498,7 @@ void __timer_interrupt(void) *next_tb = ~(u64)0; if (evt->event_handler) evt->event_handler(evt); - __get_cpu_var(irq_stat).timer_irqs_event++; + __this_cpu_inc(irq_stat.timer_irqs_event); } else { now = *next_tb - now; if (now <= DECREMENTER_MAX) @@ -506,13 +506,13 @@ void __timer_interrupt(void) /* We may have raced with new irq work */ if (test_irq_work_pending()) set_dec(1); - __get_cpu_var(irq_stat).timer_irqs_others++; + __this_cpu_inc(irq_stat.timer_irqs_others); } #ifdef CONFIG_PPC64 /* collect purr register values often, for accurate calculations */ if (firmware_has_feature(FW_FEATURE_SPLPAR)) { - struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); + struct cpu_usage *cu = this_cpu_ptr(&cpu_usage_array); cu->current_tb = mfspr(SPRN_PURR); } #endif @@ -527,7 +527,7 @@ void __timer_interrupt(void) void timer_interrupt(struct pt_regs * regs) { struct pt_regs *old_regs; - u64 *next_tb = &__get_cpu_var(decrementers_next_tb); + u64 *next_tb = this_cpu_ptr(&decrementers_next_tb); /* Ensure a positive value is written to the decrementer, or else * some CPUs will continue to take decrementer exceptions. @@ -813,7 +813,7 @@ static void __init clocksource_init(void) static int decrementer_set_next_event(unsigned long evt, struct clock_event_device *dev) { - __get_cpu_var(decrementers_next_tb) = get_tb_or_rtc() + evt; + __this_cpu_write(decrementers_next_tb, get_tb_or_rtc() + evt); set_dec(evt); /* We may have raced with new irq work */ @@ -833,7 +833,7 @@ static void decrementer_set_mode(enum clock_event_mode mode, /* Interrupt handler for the timer broadcast IPI */ void tick_broadcast_ipi_handler(void) { - u64 *next_tb = &__get_cpu_var(decrementers_next_tb); + u64 *next_tb = this_cpu_ptr(&decrementers_next_tb); *next_tb = get_tb_or_rtc(); __timer_interrupt(); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 0dc43f9932cf..e6595b72269b 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -295,7 +295,7 @@ long machine_check_early(struct pt_regs *regs) { long handled = 0; - __get_cpu_var(irq_stat).mce_exceptions++; + __this_cpu_inc(irq_stat.mce_exceptions); if (cur_cpu_spec && cur_cpu_spec->machine_check_early) handled = cur_cpu_spec->machine_check_early(regs); @@ -304,7 +304,7 @@ long machine_check_early(struct pt_regs *regs) long hmi_exception_realmode(struct pt_regs *regs) { - __get_cpu_var(irq_stat).hmi_exceptions++; + __this_cpu_inc(irq_stat.hmi_exceptions); if (ppc_md.hmi_exception_early) ppc_md.hmi_exception_early(regs); @@ -700,7 +700,7 @@ void machine_check_exception(struct pt_regs *regs) enum ctx_state prev_state = exception_enter(); int recover = 0; - __get_cpu_var(irq_stat).mce_exceptions++; + __this_cpu_inc(irq_stat.mce_exceptions); /* See if any machine dependent calls. In theory, we would want * to call the CPU first, and call the ppc_md. one if the CPU @@ -1519,7 +1519,7 @@ void vsx_unavailable_tm(struct pt_regs *regs) void performance_monitor_exception(struct pt_regs *regs) { - __get_cpu_var(irq_stat).pmu_irqs++; + __this_cpu_inc(irq_stat.pmu_irqs); perf_irq(regs); } diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c index 2e02ed849f36..16095841afe1 100644 --- a/arch/powerpc/kvm/e500.c +++ b/arch/powerpc/kvm/e500.c @@ -76,11 +76,11 @@ static inline int local_sid_setup_one(struct id *entry) unsigned long sid; int ret = -1; - sid = ++(__get_cpu_var(pcpu_last_used_sid)); + sid = __this_cpu_inc_return(pcpu_last_used_sid); if (sid < NUM_TIDS) { - __get_cpu_var(pcpu_sids).entry[sid] = entry; + __this_cpu_write(pcpu_sids)entry[sid], entry); entry->val = sid; - entry->pentry = &__get_cpu_var(pcpu_sids).entry[sid]; + entry->pentry = this_cpu_ptr(&pcpu_sids.entry[sid]); ret = sid; } @@ -108,8 +108,8 @@ static inline int local_sid_setup_one(struct id *entry) static inline int local_sid_lookup(struct id *entry) { if (entry && entry->val != 0 && - __get_cpu_var(pcpu_sids).entry[entry->val] == entry && - entry->pentry == &__get_cpu_var(pcpu_sids).entry[entry->val]) + __this_cpu_read(pcpu_sids.entry[entry->val]) == entry && + entry->pentry == this_cpu_ptr(&pcpu_sids.entry[entry->val])) return entry->val; return -1; } @@ -117,8 +117,8 @@ static inline int local_sid_lookup(struct id *entry) /* Invalidate all id mappings on local core -- call with preempt disabled */ static inline void local_sid_destroy_all(void) { - __get_cpu_var(pcpu_last_used_sid) = 0; - memset(&__get_cpu_var(pcpu_sids), 0, sizeof(__get_cpu_var(pcpu_sids))); + __this_cpu_write(pcpu_last_used_sid, 0); + memset(this_cpu_ptr(&pcpu_sids), 0, sizeof(pcpu_sids)); } static void *kvmppc_e500_id_table_alloc(struct kvmppc_vcpu_e500 *vcpu_e500) diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c index 164bad2a19bf..6ef54e523f33 100644 --- a/arch/powerpc/kvm/e500mc.c +++ b/arch/powerpc/kvm/e500mc.c @@ -141,9 +141,9 @@ static void kvmppc_core_vcpu_load_e500mc(struct kvm_vcpu *vcpu, int cpu) mtspr(SPRN_GESR, vcpu->arch.shared->esr); if (vcpu->arch.oldpir != mfspr(SPRN_PIR) || - __get_cpu_var(last_vcpu_of_lpid)[vcpu->kvm->arch.lpid] != vcpu) { + __this_cpu_read(last_vcpu_of_lpid[vcpu->kvm->arch.lpid]) != vcpu) { kvmppc_e500_tlbil_all(vcpu_e500); - __get_cpu_var(last_vcpu_of_lpid)[vcpu->kvm->arch.lpid] = vcpu; + __this_cpu_write(last_vcpu_of_lpid[vcpu->kvm->arch.lpid], vcpu); } kvmppc_load_guest_fp(vcpu); diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index afc0a8295f84..504a16f1a1a0 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -625,7 +625,7 @@ static void native_flush_hash_range(unsigned long number, int local) unsigned long want_v; unsigned long flags; real_pte_t pte; - struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); unsigned long psize = batch->psize; int ssize = batch->ssize; int i; diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index daee7f4e5a14..060d51fda35e 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1314,7 +1314,7 @@ void flush_hash_range(unsigned long number, int local) else { int i; struct ppc64_tlb_batch *batch = - &__get_cpu_var(ppc64_tlb_batch); + this_cpu_ptr(&ppc64_tlb_batch); for (i = 0; i < number; i++) flush_hash_page(batch->vpn[i], batch->pte[i], diff --git a/arch/powerpc/mm/hugetlbpage-book3e.c b/arch/powerpc/mm/hugetlbpage-book3e.c index 5e4ee2573903..ba47aaf33a4b 100644 --- a/arch/powerpc/mm/hugetlbpage-book3e.c +++ b/arch/powerpc/mm/hugetlbpage-book3e.c @@ -33,13 +33,13 @@ static inline int tlb1_next(void) ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; - index = __get_cpu_var(next_tlbcam_idx); + index = this_cpu_read(next_tlbcam_idx); /* Just round-robin the entries and wrap when we hit the end */ if (unlikely(index == ncams - 1)) - __get_cpu_var(next_tlbcam_idx) = tlbcam_index; + __this_cpu_write(next_tlbcam_idx, tlbcam_index); else - __get_cpu_var(next_tlbcam_idx)++; + __this_cpu_inc(next_tlbcam_idx); return index; } diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 7e70ae968e5f..8aa04f03fd31 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -462,7 +462,7 @@ static void hugepd_free(struct mmu_gather *tlb, void *hugepte) { struct hugepd_freelist **batchp; - batchp = &get_cpu_var(hugepd_freelist_cur); + batchp = this_cpu_ptr(&hugepd_freelist_cur); if (atomic_read(&tlb->mm->mm_users) < 2 || cpumask_equal(mm_cpumask(tlb->mm), diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index b7cd00b0171e..690f9c7bf3c8 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -339,7 +339,7 @@ static void power_pmu_bhrb_reset(void) static void power_pmu_bhrb_enable(struct perf_event *event) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); if (!ppmu->bhrb_nr) return; @@ -354,7 +354,7 @@ static void power_pmu_bhrb_enable(struct perf_event *event) static void power_pmu_bhrb_disable(struct perf_event *event) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); if (!ppmu->bhrb_nr) return; @@ -1144,7 +1144,7 @@ static void power_pmu_disable(struct pmu *pmu) if (!ppmu) return; local_irq_save(flags); - cpuhw = &__get_cpu_var(cpu_hw_events); + cpuhw = this_cpu_ptr(&cpu_hw_events); if (!cpuhw->disabled) { /* @@ -1211,7 +1211,7 @@ static void power_pmu_enable(struct pmu *pmu) return; local_irq_save(flags); - cpuhw = &__get_cpu_var(cpu_hw_events); + cpuhw = this_cpu_ptr(&cpu_hw_events); if (!cpuhw->disabled) goto out; @@ -1403,7 +1403,7 @@ static int power_pmu_add(struct perf_event *event, int ef_flags) * Add the event to the list (if there is room) * and check whether the total set is still feasible. */ - cpuhw = &__get_cpu_var(cpu_hw_events); + cpuhw = this_cpu_ptr(&cpu_hw_events); n0 = cpuhw->n_events; if (n0 >= ppmu->n_counter) goto out; @@ -1469,7 +1469,7 @@ static void power_pmu_del(struct perf_event *event, int ef_flags) power_pmu_read(event); - cpuhw = &__get_cpu_var(cpu_hw_events); + cpuhw = this_cpu_ptr(&cpu_hw_events); for (i = 0; i < cpuhw->n_events; ++i) { if (event == cpuhw->event[i]) { while (++i < cpuhw->n_events) { @@ -1575,7 +1575,7 @@ static void power_pmu_stop(struct perf_event *event, int ef_flags) */ void power_pmu_start_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); perf_pmu_disable(pmu); cpuhw->group_flag |= PERF_EVENT_TXN; @@ -1589,7 +1589,7 @@ void power_pmu_start_txn(struct pmu *pmu) */ void power_pmu_cancel_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); cpuhw->group_flag &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); @@ -1607,7 +1607,7 @@ int power_pmu_commit_txn(struct pmu *pmu) if (!ppmu) return -EAGAIN; - cpuhw = &__get_cpu_var(cpu_hw_events); + cpuhw = this_cpu_ptr(&cpu_hw_events); n = cpuhw->n_events; if (check_excludes(cpuhw->event, cpuhw->flags, 0, n)) return -EAGAIN; @@ -1964,7 +1964,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, if (event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK) { struct cpu_hw_events *cpuhw; - cpuhw = &__get_cpu_var(cpu_hw_events); + cpuhw = this_cpu_ptr(&cpu_hw_events); power_pmu_bhrb_read(cpuhw); data.br_stack = &cpuhw->bhrb_stack; } @@ -2037,7 +2037,7 @@ static bool pmc_overflow(unsigned long val) static void perf_event_interrupt(struct pt_regs *regs) { int i, j; - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); struct perf_event *event; unsigned long val[8]; int found, active; diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c index d35ae52c69dc..4acaea01fe03 100644 --- a/arch/powerpc/perf/core-fsl-emb.c +++ b/arch/powerpc/perf/core-fsl-emb.c @@ -210,7 +210,7 @@ static void fsl_emb_pmu_disable(struct pmu *pmu) unsigned long flags; local_irq_save(flags); - cpuhw = &__get_cpu_var(cpu_hw_events); + cpuhw = this_cpu_ptr(&cpu_hw_events); if (!cpuhw->disabled) { cpuhw->disabled = 1; @@ -249,7 +249,7 @@ static void fsl_emb_pmu_enable(struct pmu *pmu) unsigned long flags; local_irq_save(flags); - cpuhw = &__get_cpu_var(cpu_hw_events); + cpuhw = this_cpu_ptr(&cpu_hw_events); if (!cpuhw->disabled) goto out; @@ -653,7 +653,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, static void perf_event_interrupt(struct pt_regs *regs) { int i; - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); struct perf_event *event; unsigned long val; int found = 0; diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 8a106b4172e0..4c11421847be 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -82,7 +82,7 @@ static void iic_unmask(struct irq_data *d) static void iic_eoi(struct irq_data *d) { - struct iic *iic = &__get_cpu_var(cpu_iic); + struct iic *iic = this_cpu_ptr(&cpu_iic); out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]); BUG_ON(iic->eoi_ptr < 0); } @@ -148,7 +148,7 @@ static unsigned int iic_get_irq(void) struct iic *iic; unsigned int virq; - iic = &__get_cpu_var(cpu_iic); + iic = this_cpu_ptr(&cpu_iic); *(unsigned long *) &pending = in_be64((u64 __iomem *) &iic->regs->pending_destr); if (!(pending.flags & CBE_IIC_IRQ_VALID)) @@ -163,7 +163,7 @@ static unsigned int iic_get_irq(void) void iic_setup_cpu(void) { - out_be64(&__get_cpu_var(cpu_iic).regs->prio, 0xff); + out_be64(this_cpu_ptr(&cpu_iic.regs->prio), 0xff); } u8 iic_get_target_id(int cpu) diff --git a/arch/powerpc/platforms/powernv/opal-tracepoints.c b/arch/powerpc/platforms/powernv/opal-tracepoints.c index d8a000a9988b..9527e2a7c541 100644 --- a/arch/powerpc/platforms/powernv/opal-tracepoints.c +++ b/arch/powerpc/platforms/powernv/opal-tracepoints.c @@ -48,7 +48,7 @@ void __trace_opal_entry(unsigned long opcode, unsigned long *args) local_irq_save(flags); - depth = &__get_cpu_var(opal_trace_depth); + depth = this_cpu_ptr(&opal_trace_depth); if (*depth) goto out; @@ -69,7 +69,7 @@ void __trace_opal_exit(long opcode, unsigned long retval) local_irq_save(flags); - depth = &__get_cpu_var(opal_trace_depth); + depth = this_cpu_ptr(&opal_trace_depth); if (*depth) goto out; diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 5f3b23220b8e..a6c42f34303a 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -711,7 +711,7 @@ void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq) static unsigned int ps3_get_irq(void) { - struct ps3_private *pd = &__get_cpu_var(ps3_private); + struct ps3_private *pd = this_cpu_ptr(&ps3_private); u64 x = (pd->bmp.status & pd->bmp.mask); unsigned int plug; diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index 1062f71f5a85..39049e4884fb 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -75,7 +75,7 @@ static atomic_t dtl_count; */ static void consume_dtle(struct dtl_entry *dtle, u64 index) { - struct dtl_ring *dtlr = &__get_cpu_var(dtl_rings); + struct dtl_ring *dtlr = this_cpu_ptr(&dtl_rings); struct dtl_entry *wp = dtlr->write_ptr; struct lppaca *vpa = local_paca->lppaca_ptr; diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index 4575f0c9e521..f02ec3ab428c 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c @@ -110,7 +110,7 @@ static void probe_hcall_entry(void *ignored, unsigned long opcode, unsigned long if (opcode > MAX_HCALL_OPCODE) return; - h = &__get_cpu_var(hcall_stats)[opcode / 4]; + h = this_cpu_ptr(&hcall_stats[opcode / 4]); h->tb_start = mftb(); h->purr_start = mfspr(SPRN_PURR); } @@ -123,7 +123,7 @@ static void probe_hcall_exit(void *ignored, unsigned long opcode, unsigned long if (opcode > MAX_HCALL_OPCODE) return; - h = &__get_cpu_var(hcall_stats)[opcode / 4]; + h = this_cpu_ptr(&hcall_stats[opcode / 4]); h->num_calls++; h->tb_total += mftb() - h->tb_start; h->purr_total += mfspr(SPRN_PURR) - h->purr_start; diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 4642d6a4d356..8c355ed4291e 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -200,7 +200,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, local_irq_save(flags); /* to protect tcep and the page behind it */ - tcep = __get_cpu_var(tce_page); + tcep = __this_cpu_read(tce_page); /* This is safe to do since interrupts are off when we're called * from iommu_alloc{,_sg}() @@ -213,7 +213,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, direction, attrs); } - __get_cpu_var(tce_page) = tcep; + __this_cpu_write(tce_page, tcep); } rpn = __pa(uaddr) >> TCE_SHIFT; @@ -399,7 +399,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, long l, limit; local_irq_disable(); /* to protect tcep and the page behind it */ - tcep = __get_cpu_var(tce_page); + tcep = __this_cpu_read(tce_page); if (!tcep) { tcep = (__be64 *)__get_free_page(GFP_ATOMIC); @@ -407,7 +407,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, local_irq_enable(); return -ENOMEM; } - __get_cpu_var(tce_page) = tcep; + __this_cpu_write(tce_page, tcep); } proto_tce = TCE_PCI_READ | TCE_PCI_WRITE; diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 34e64237fff9..56df72da59fe 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -507,7 +507,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) unsigned long vpn; unsigned long i, pix, rc; unsigned long flags = 0; - struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); unsigned long param[9]; unsigned long hash, index, shift, hidx, slot; @@ -697,7 +697,7 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args) local_irq_save(flags); - depth = &__get_cpu_var(hcall_trace_depth); + depth = this_cpu_ptr(&hcall_trace_depth); if (*depth) goto out; @@ -722,7 +722,7 @@ void __trace_hcall_exit(long opcode, unsigned long retval, local_irq_save(flags); - depth = &__get_cpu_var(hcall_trace_depth); + depth = this_cpu_ptr(&hcall_trace_depth); if (*depth) goto out; diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index dff05b9eb946..179a69fd5568 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -302,8 +302,8 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) /* If it isn't an extended log we can use the per cpu 64bit buffer */ h = (struct rtas_error_log *)&savep[1]; if (!rtas_error_extended(h)) { - memcpy(&__get_cpu_var(mce_data_buf), h, sizeof(__u64)); - errhdr = (struct rtas_error_log *)&__get_cpu_var(mce_data_buf); + memcpy(this_cpu_ptr(&mce_data_buf), h, sizeof(__u64)); + errhdr = (struct rtas_error_log *)this_cpu_ptr(&mce_data_buf); } else { int len, error_log_length; diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index fe0cca477164..365249cd346b 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -155,7 +155,7 @@ int __init xics_smp_probe(void) void xics_teardown_cpu(void) { - struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); + struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); /* * we have to reset the cppr index to 0 because we're -- GitLab From b4f501916ce2ae80c28017814d71d1bf83679271 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:50 -0500 Subject: [PATCH 0668/5088] tile: Replace __get_cpu_var uses __get_cpu_var() is used for multiple purposes in the kernel source. One of them is address calculation via the form &__get_cpu_var(x). This calculates the address for the instance of the percpu variable of the current processor based on an offset. Other use cases are for storing and retrieving data from the current processors percpu area. __get_cpu_var() can be used as an lvalue when writing data or on the right side of an assignment. __get_cpu_var() is defined as : #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) __get_cpu_var() always only does an address determination. However, store and retrieve operations could use a segment prefix (or global register on other platforms) to avoid the address calculation. this_cpu_write() and this_cpu_read() can directly take an offset into a percpu area and use optimized assembly code to read and write per cpu variables. This patch converts __get_cpu_var into either an explicit address calculation using this_cpu_ptr() or into a use of this_cpu operations that use the offset. Thereby address calculations are avoided and less registers are used when code is generated. At the end of the patch set all uses of __get_cpu_var have been removed so the macro is removed too. The patch set includes passes over all arches as well. Once these operations are used throughout then specialized macros can be defined in non -x86 arches as well in order to optimize per cpu access by f.e. using a global register that may be set to the per cpu base. Transformations done to __get_cpu_var() 1. Determine the address of the percpu instance of the current processor. DEFINE_PER_CPU(int, y); int *x = &__get_cpu_var(y); Converts to int *x = this_cpu_ptr(&y); 2. Same as #1 but this time an array structure is involved. DEFINE_PER_CPU(int, y[20]); int *x = __get_cpu_var(y); Converts to int *x = this_cpu_ptr(y); 3. Retrieve the content of the current processors instance of a per cpu variable. DEFINE_PER_CPU(int, y); int x = __get_cpu_var(y) Converts to int x = __this_cpu_read(y); 4. Retrieve the content of a percpu struct DEFINE_PER_CPU(struct mystruct, y); struct mystruct x = __get_cpu_var(y); Converts to memcpy(&x, this_cpu_ptr(&y), sizeof(x)); 5. Assignment to a per cpu variable DEFINE_PER_CPU(int, y) __get_cpu_var(y) = x; Converts to __this_cpu_write(y, x); 6. Increment/Decrement etc of a per cpu variable DEFINE_PER_CPU(int, y); __get_cpu_var(y)++ Converts to __this_cpu_inc(y) Acked-by: Chris Metcalf Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/tile/include/asm/irqflags.h | 4 ++-- arch/tile/include/asm/mmu_context.h | 6 +++--- arch/tile/kernel/irq.c | 14 +++++++------- arch/tile/kernel/messaging.c | 4 ++-- arch/tile/kernel/process.c | 2 +- arch/tile/kernel/setup.c | 3 ++- arch/tile/kernel/single_step.c | 4 ++-- arch/tile/kernel/smp.c | 2 +- arch/tile/kernel/smpboot.c | 6 +++--- arch/tile/kernel/time.c | 8 ++++---- arch/tile/mm/highmem.c | 2 +- arch/tile/mm/init.c | 4 ++-- 12 files changed, 30 insertions(+), 29 deletions(-) diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h index 71af5747874d..60d62a292fce 100644 --- a/arch/tile/include/asm/irqflags.h +++ b/arch/tile/include/asm/irqflags.h @@ -140,12 +140,12 @@ extern unsigned int debug_smp_processor_id(void); /* * Read the set of maskable interrupts. - * We avoid the preemption warning here via __this_cpu_ptr since even + * We avoid the preemption warning here via raw_cpu_ptr since even * if irqs are already enabled, it's harmless to read the wrong cpu's * enabled mask. */ #define arch_local_irqs_enabled() \ - (*__this_cpu_ptr(&interrupts_enabled_mask)) + (*raw_cpu_ptr(&interrupts_enabled_mask)) /* Re-enable all maskable interrupts. */ #define arch_local_irq_enable() \ diff --git a/arch/tile/include/asm/mmu_context.h b/arch/tile/include/asm/mmu_context.h index 4734215e2ad4..f67753db1f78 100644 --- a/arch/tile/include/asm/mmu_context.h +++ b/arch/tile/include/asm/mmu_context.h @@ -84,7 +84,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *t) * clear any pending DMA interrupts. */ if (current->thread.tile_dma_state.enabled) - install_page_table(mm->pgd, __get_cpu_var(current_asid)); + install_page_table(mm->pgd, __this_cpu_read(current_asid)); #endif } @@ -96,12 +96,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, int cpu = smp_processor_id(); /* Pick new ASID. */ - int asid = __get_cpu_var(current_asid) + 1; + int asid = __this_cpu_read(current_asid) + 1; if (asid > max_asid) { asid = min_asid; local_flush_tlb(); } - __get_cpu_var(current_asid) = asid; + __this_cpu_write(current_asid, asid); /* Clear cpu from the old mm, and set it in the new one. */ cpumask_clear_cpu(cpu, mm_cpumask(prev)); diff --git a/arch/tile/kernel/irq.c b/arch/tile/kernel/irq.c index 637f2ffaa5f5..ba85765e1436 100644 --- a/arch/tile/kernel/irq.c +++ b/arch/tile/kernel/irq.c @@ -73,7 +73,7 @@ static DEFINE_PER_CPU(int, irq_depth); */ void tile_dev_intr(struct pt_regs *regs, int intnum) { - int depth = __get_cpu_var(irq_depth)++; + int depth = __this_cpu_inc_return(irq_depth); unsigned long original_irqs; unsigned long remaining_irqs; struct pt_regs *old_regs; @@ -120,7 +120,7 @@ void tile_dev_intr(struct pt_regs *regs, int intnum) /* Count device irqs; Linux IPIs are counted elsewhere. */ if (irq != IRQ_RESCHEDULE) - __get_cpu_var(irq_stat).irq_dev_intr_count++; + __this_cpu_inc(irq_stat.irq_dev_intr_count); generic_handle_irq(irq); } @@ -130,10 +130,10 @@ void tile_dev_intr(struct pt_regs *regs, int intnum) * including any that were reenabled during interrupt * handling. */ - if (depth == 0) - unmask_irqs(~__get_cpu_var(irq_disable_mask)); + if (depth == 1) + unmask_irqs(~__this_cpu_read(irq_disable_mask)); - __get_cpu_var(irq_depth)--; + __this_cpu_dec(irq_depth); /* * Track time spent against the current process again and @@ -151,7 +151,7 @@ void tile_dev_intr(struct pt_regs *regs, int intnum) static void tile_irq_chip_enable(struct irq_data *d) { get_cpu_var(irq_disable_mask) &= ~(1UL << d->irq); - if (__get_cpu_var(irq_depth) == 0) + if (__this_cpu_read(irq_depth) == 0) unmask_irqs(1UL << d->irq); put_cpu_var(irq_disable_mask); } @@ -197,7 +197,7 @@ static void tile_irq_chip_ack(struct irq_data *d) */ static void tile_irq_chip_eoi(struct irq_data *d) { - if (!(__get_cpu_var(irq_disable_mask) & (1UL << d->irq))) + if (!(__this_cpu_read(irq_disable_mask) & (1UL << d->irq))) unmask_irqs(1UL << d->irq); } diff --git a/arch/tile/kernel/messaging.c b/arch/tile/kernel/messaging.c index 7867266f9716..ac950be1318e 100644 --- a/arch/tile/kernel/messaging.c +++ b/arch/tile/kernel/messaging.c @@ -28,7 +28,7 @@ static DEFINE_PER_CPU(HV_MsgState, msg_state); void init_messaging(void) { /* Allocate storage for messages in kernel space */ - HV_MsgState *state = &__get_cpu_var(msg_state); + HV_MsgState *state = this_cpu_ptr(&msg_state); int rc = hv_register_message_state(state); if (rc != HV_OK) panic("hv_register_message_state: error %d", rc); @@ -96,7 +96,7 @@ void hv_message_intr(struct pt_regs *regs, int intnum) struct hv_driver_cb *cb = (struct hv_driver_cb *)him->intarg; cb->callback(cb, him->intdata); - __get_cpu_var(irq_stat).irq_hv_msg_count++; + __this_cpu_inc(irq_stat.irq_hv_msg_count); } } diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 16ed58948757..0050cbc1d9de 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -64,7 +64,7 @@ early_param("idle", idle_setup); void arch_cpu_idle(void) { - __get_cpu_var(irq_stat).idle_timestamp = jiffies; + __this_cpu_write(irq_stat.idle_timestamp, jiffies); _cpu_idle(); } diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index 112ababa9e55..b9736ded06f2 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c @@ -1218,7 +1218,8 @@ static void __init validate_hv(void) * various asid variables to their appropriate initial states. */ asid_range = hv_inquire_asid(0); - __get_cpu_var(current_asid) = min_asid = asid_range.start; + min_asid = asid_range.start; + __this_cpu_write(current_asid, min_asid); max_asid = asid_range.start + asid_range.size - 1; if (hv_confstr(HV_CONFSTR_CHIP_MODEL, (HV_VirtAddr)chip_model, diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index de07fa7d1315..6cb2ce31b5a2 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c @@ -740,7 +740,7 @@ static DEFINE_PER_CPU(unsigned long, ss_saved_pc); void gx_singlestep_handle(struct pt_regs *regs, int fault_num) { - unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc); + unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc); struct thread_info *info = (void *)current_thread_info(); int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K); @@ -766,7 +766,7 @@ void gx_singlestep_handle(struct pt_regs *regs, int fault_num) void single_step_once(struct pt_regs *regs) { - unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc); + unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc); unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K); *ss_pc = regs->pc; diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c index 01e8ab29f43a..3dbedb0174b3 100644 --- a/arch/tile/kernel/smp.c +++ b/arch/tile/kernel/smp.c @@ -188,7 +188,7 @@ void flush_icache_range(unsigned long start, unsigned long end) /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ static irqreturn_t handle_reschedule_ipi(int irq, void *token) { - __get_cpu_var(irq_stat).irq_resched_count++; + __this_cpu_inc(irq_stat.irq_resched_count); scheduler_ipi(); return IRQ_HANDLED; diff --git a/arch/tile/kernel/smpboot.c b/arch/tile/kernel/smpboot.c index 732e9d138661..0d59a1b60c74 100644 --- a/arch/tile/kernel/smpboot.c +++ b/arch/tile/kernel/smpboot.c @@ -41,7 +41,7 @@ void __init smp_prepare_boot_cpu(void) int cpu = smp_processor_id(); set_cpu_online(cpu, 1); set_cpu_present(cpu, 1); - __get_cpu_var(cpu_state) = CPU_ONLINE; + __this_cpu_write(cpu_state, CPU_ONLINE); init_messaging(); } @@ -158,7 +158,7 @@ static void start_secondary(void) /* printk(KERN_DEBUG "Initializing CPU#%d\n", cpuid); */ /* Initialize the current asid for our first page table. */ - __get_cpu_var(current_asid) = min_asid; + __this_cpu_write(current_asid, min_asid); /* Set up this thread as another owner of the init_mm */ atomic_inc(&init_mm.mm_count); @@ -201,7 +201,7 @@ void online_secondary(void) notify_cpu_starting(smp_processor_id()); set_cpu_online(smp_processor_id(), 1); - __get_cpu_var(cpu_state) = CPU_ONLINE; + __this_cpu_write(cpu_state, CPU_ONLINE); /* Set up tile-specific state for this cpu. */ setup_cpu(0); diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c index d8fbc289e680..ab1c9fe2aa7f 100644 --- a/arch/tile/kernel/time.c +++ b/arch/tile/kernel/time.c @@ -162,7 +162,7 @@ static DEFINE_PER_CPU(struct clock_event_device, tile_timer) = { void setup_tile_timer(void) { - struct clock_event_device *evt = &__get_cpu_var(tile_timer); + struct clock_event_device *evt = this_cpu_ptr(&tile_timer); /* Fill in fields that are speed-specific. */ clockevents_calc_mult_shift(evt, cycles_per_sec, TILE_MINSEC); @@ -182,7 +182,7 @@ void setup_tile_timer(void) void do_timer_interrupt(struct pt_regs *regs, int fault_num) { struct pt_regs *old_regs = set_irq_regs(regs); - struct clock_event_device *evt = &__get_cpu_var(tile_timer); + struct clock_event_device *evt = this_cpu_ptr(&tile_timer); /* * Mask the timer interrupt here, since we are a oneshot timer @@ -194,7 +194,7 @@ void do_timer_interrupt(struct pt_regs *regs, int fault_num) irq_enter(); /* Track interrupt count. */ - __get_cpu_var(irq_stat).irq_timer_count++; + __this_cpu_inc(irq_stat.irq_timer_count); /* Call the generic timer handler */ evt->event_handler(evt); @@ -235,7 +235,7 @@ cycles_t ns2cycles(unsigned long nsecs) * We do not have to disable preemption here as each core has the same * clock frequency. */ - struct clock_event_device *dev = &__raw_get_cpu_var(tile_timer); + struct clock_event_device *dev = raw_cpu_ptr(&tile_timer); /* * as in clocksource.h and x86's timer.h, we split the calculation diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c index 0dc218294770..6aa2f2625447 100644 --- a/arch/tile/mm/highmem.c +++ b/arch/tile/mm/highmem.c @@ -103,7 +103,7 @@ static void kmap_atomic_register(struct page *page, int type, spin_lock(&_lock); /* With interrupts disabled, now fill in the per-cpu info. */ - amp = &__get_cpu_var(amps).per_type[type]; + amp = this_cpu_ptr(&s.per_type[type]); amp->page = page; amp->cpu = smp_processor_id(); amp->va = va; diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c index bfb3127b4df9..f46a152b09e6 100644 --- a/arch/tile/mm/init.c +++ b/arch/tile/mm/init.c @@ -593,14 +593,14 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) interrupt_mask_set_mask(-1ULL); rc = flush_and_install_context(__pa(pgtables), init_pgprot((unsigned long)pgtables), - __get_cpu_var(current_asid), + __this_cpu_read(current_asid), cpumask_bits(my_cpu_mask)); interrupt_mask_restore_mask(irqmask); BUG_ON(rc != 0); /* Copy the page table back to the normal swapper_pg_dir. */ memcpy(pgd_base, pgtables, sizeof(pgtables)); - __install_page_table(pgd_base, __get_cpu_var(current_asid), + __install_page_table(pgd_base, __this_cpu_read(current_asid), swapper_pgprot); /* -- GitLab From 81829a96869c8bad74a582705617e75758c4152d Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:51 -0500 Subject: [PATCH 0669/5088] tile: Use this_cpu_ptr() for hardware counters Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/tile/kernel/perf_event.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/tile/kernel/perf_event.c b/arch/tile/kernel/perf_event.c index 2bf6c9c135c1..bb509cee3b59 100644 --- a/arch/tile/kernel/perf_event.c +++ b/arch/tile/kernel/perf_event.c @@ -590,7 +590,7 @@ static int tile_event_set_period(struct perf_event *event) */ static void tile_pmu_stop(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; @@ -616,7 +616,7 @@ static void tile_pmu_stop(struct perf_event *event, int flags) */ static void tile_pmu_start(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int idx = event->hw.idx; if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) @@ -650,7 +650,7 @@ static void tile_pmu_start(struct perf_event *event, int flags) */ static int tile_pmu_add(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc; unsigned long mask; int b, max_cnt; @@ -706,7 +706,7 @@ static int tile_pmu_add(struct perf_event *event, int flags) */ static void tile_pmu_del(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int i; /* @@ -880,14 +880,14 @@ static struct pmu tilera_pmu = { int tile_pmu_handle_irq(struct pt_regs *regs, int fault) { struct perf_sample_data data; - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct perf_event *event; struct hw_perf_event *hwc; u64 val; unsigned long status; int bit; - __get_cpu_var(perf_irqs)++; + __this_cpu_inc(perf_irqs); if (!atomic_read(&tile_active_events)) return 0; -- GitLab From 7e788ab11d73fbb617973c12a9b3f84f93721e67 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:52 -0500 Subject: [PATCH 0670/5088] blackfin: Replace __get_cpu_var uses __get_cpu_var() is used for multiple purposes in the kernel source. One of them is address calculation via the form &__get_cpu_var(x). This calculates the address for the instance of the percpu variable of the current processor based on an offset. Other use cases are for storing and retrieving data from the current processors percpu area. __get_cpu_var() can be used as an lvalue when writing data or on the right side of an assignment. __get_cpu_var() is defined as : #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) __get_cpu_var() always only does an address determination. However, store and retrieve operations could use a segment prefix (or global register on other platforms) to avoid the address calculation. this_cpu_write() and this_cpu_read() can directly take an offset into a percpu area and use optimized assembly code to read and write per cpu variables. This patch converts __get_cpu_var into either an explicit address calculation using this_cpu_ptr() or into a use of this_cpu operations that use the offset. Thereby address calculations are avoided and less registers are used when code is generated. At the end of the patch set all uses of __get_cpu_var have been removed so the macro is removed too. The patch set includes passes over all arches as well. Once these operations are used throughout then specialized macros can be defined in non -x86 arches as well in order to optimize per cpu access by f.e. using a global register that may be set to the per cpu base. Transformations done to __get_cpu_var() 1. Determine the address of the percpu instance of the current processor. DEFINE_PER_CPU(int, y); int *x = &__get_cpu_var(y); Converts to int *x = this_cpu_ptr(&y); 2. Same as #1 but this time an array structure is involved. DEFINE_PER_CPU(int, y[20]); int *x = __get_cpu_var(y); Converts to int *x = this_cpu_ptr(y); 3. Retrieve the content of the current processors instance of a per cpu variable. DEFINE_PER_CPU(int, y); int x = __get_cpu_var(y) Converts to int x = __this_cpu_read(y); 4. Retrieve the content of a percpu struct DEFINE_PER_CPU(struct mystruct, y); struct mystruct x = __get_cpu_var(y); Converts to memcpy(&x, this_cpu_ptr(&y), sizeof(x)); 5. Assignment to a per cpu variable DEFINE_PER_CPU(int, y) __get_cpu_var(y) = x; Converts to __this_cpu_write(y, x); 6. Increment/Decrement etc of a per cpu variable DEFINE_PER_CPU(int, y); __get_cpu_var(y)++ Converts to __this_cpu_inc(y) CC: Mike Frysinger Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/blackfin/include/asm/ipipe.h | 2 +- arch/blackfin/kernel/perf_event.c | 10 +++++----- arch/blackfin/mach-common/ints-priority.c | 8 ++++---- arch/blackfin/mach-common/smp.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/blackfin/include/asm/ipipe.h b/arch/blackfin/include/asm/ipipe.h index 17b5e92e3bc6..fe1160fbff91 100644 --- a/arch/blackfin/include/asm/ipipe.h +++ b/arch/blackfin/include/asm/ipipe.h @@ -157,7 +157,7 @@ static inline unsigned long __ipipe_ffnz(unsigned long ul) } #define __ipipe_do_root_xirq(ipd, irq) \ - ((ipd)->irqs[irq].handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs))) + ((ipd)->irqs[irq].handler(irq, raw_cpu_ptr(&__ipipe_tick_regs))) #define __ipipe_run_irqtail(irq) /* Must be a macro */ \ do { \ diff --git a/arch/blackfin/kernel/perf_event.c b/arch/blackfin/kernel/perf_event.c index ea2032013cc2..1e9c8b0bf486 100644 --- a/arch/blackfin/kernel/perf_event.c +++ b/arch/blackfin/kernel/perf_event.c @@ -300,7 +300,7 @@ static void bfin_perf_event_update(struct perf_event *event, static void bfin_pmu_stop(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; @@ -318,7 +318,7 @@ static void bfin_pmu_stop(struct perf_event *event, int flags) static void bfin_pmu_start(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; @@ -335,7 +335,7 @@ static void bfin_pmu_start(struct perf_event *event, int flags) static void bfin_pmu_del(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); bfin_pmu_stop(event, PERF_EF_UPDATE); __clear_bit(event->hw.idx, cpuc->used_mask); @@ -345,7 +345,7 @@ static void bfin_pmu_del(struct perf_event *event, int flags) static int bfin_pmu_add(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; int ret = -EAGAIN; @@ -421,7 +421,7 @@ static int bfin_pmu_event_init(struct perf_event *event) static void bfin_pmu_enable(struct pmu *pmu) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct perf_event *event; struct hw_perf_event *hwc; int i; diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index 1f94784eab6d..e5910e9bc4ac 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -1309,12 +1309,12 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs) bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */ #endif /* This is basically what we need from the register frame. */ - __raw_get_cpu_var(__ipipe_tick_regs).ipend = regs->ipend; - __raw_get_cpu_var(__ipipe_tick_regs).pc = regs->pc; + __this_cpu_write(__ipipe_tick_regs.ipend, regs->ipend); + __this_cpu_write(__ipipe_tick_regs.pc, regs->pc); if (this_domain != ipipe_root_domain) - __raw_get_cpu_var(__ipipe_tick_regs).ipend &= ~0x10; + __this_cpu_and(__ipipe_tick_regs.ipend, ~0x10); else - __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10; + __this_cpu_or(__ipipe_tick_regs.ipend, 0x10); } /* diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index ba6c30d8534d..8ad3e90cc8fc 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -146,7 +146,7 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance) platform_clear_ipi(cpu, IRQ_SUPPLE_1); smp_rmb(); - bfin_ipi_data = &__get_cpu_var(bfin_ipi); + bfin_ipi_data = this_cpu_ptr(&bfin_ipi); while ((pending = atomic_xchg(&bfin_ipi_data->bits, 0)) != 0) { msg = 0; do { -- GitLab From 8c23af6122e56ad30e3de259731c31a998ff5b11 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:53 -0500 Subject: [PATCH 0671/5088] avr32: Replace __get_cpu_var with __this_cpu_write Replace the single use of __get_cpu_var in avr32 with __this_cpu_write. Cc: Haavard Skinnemoen Acked-by: Hans-Christian Egtvedt Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/avr32/kernel/kprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/avr32/kernel/kprobes.c b/arch/avr32/kernel/kprobes.c index f820e9f25520..a94ece4a72c8 100644 --- a/arch/avr32/kernel/kprobes.c +++ b/arch/avr32/kernel/kprobes.c @@ -104,7 +104,7 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) static void __kprobes set_current_kprobe(struct kprobe *p) { - __get_cpu_var(current_kprobe) = p; + __this_cpu_write(current_kprobe, p); } static int __kprobes kprobe_handler(struct pt_regs *regs) -- GitLab From 494fc42170bf0747ac28e12ef13a7d388d5ff2c7 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:54 -0500 Subject: [PATCH 0672/5088] sparc: Replace __get_cpu_var uses __get_cpu_var() is used for multiple purposes in the kernel source. One of them is address calculation via the form &__get_cpu_var(x). This calculates the address for the instance of the percpu variable of the current processor based on an offset. Other use cases are for storing and retrieving data from the current processors percpu area. __get_cpu_var() can be used as an lvalue when writing data or on the right side of an assignment. __get_cpu_var() is defined as : #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) __get_cpu_var() always only does an address determination. However, store and retrieve operations could use a segment prefix (or global register on other platforms) to avoid the address calculation. this_cpu_write() and this_cpu_read() can directly take an offset into a percpu area and use optimized assembly code to read and write per cpu variables. This patch converts __get_cpu_var into either an explicit address calculation using this_cpu_ptr() or into a use of this_cpu operations that use the offset. Thereby address calculations are avoided and less registers are used when code is generated. At the end of the patch set all uses of __get_cpu_var have been removed so the macro is removed too. The patch set includes passes over all arches as well. Once these operations are used throughout then specialized macros can be defined in non -x86 arches as well in order to optimize per cpu access by f.e. using a global register that may be set to the per cpu base. Transformations done to __get_cpu_var() 1. Determine the address of the percpu instance of the current processor. DEFINE_PER_CPU(int, y); int *x = &__get_cpu_var(y); Converts to int *x = this_cpu_ptr(&y); 2. Same as #1 but this time an array structure is involved. DEFINE_PER_CPU(int, y[20]); int *x = __get_cpu_var(y); Converts to int *x = this_cpu_ptr(y); 3. Retrieve the content of the current processors instance of a per cpu variable. DEFINE_PER_CPU(int, y); int x = __get_cpu_var(y) Converts to int x = __this_cpu_read(y); 4. Retrieve the content of a percpu struct DEFINE_PER_CPU(struct mystruct, y); struct mystruct x = __get_cpu_var(y); Converts to memcpy(&x, this_cpu_ptr(&y), sizeof(x)); 5. Assignment to a per cpu variable DEFINE_PER_CPU(int, y) __get_cpu_var(y) = x; Converts to __this_cpu_write(y, x); 6. Increment/Decrement etc of a per cpu variable DEFINE_PER_CPU(int, y); __get_cpu_var(y)++ Converts to __this_cpu_inc(y) Cc: sparclinux@vger.kernel.org Acked-by: David S. Miller Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/sparc/include/asm/cpudata_32.h | 2 +- arch/sparc/include/asm/cpudata_64.h | 2 +- arch/sparc/kernel/kprobes.c | 6 +++--- arch/sparc/kernel/leon_smp.c | 2 +- arch/sparc/kernel/nmi.c | 16 ++++++++-------- arch/sparc/kernel/pci_sun4v.c | 8 ++++---- arch/sparc/kernel/perf_event.c | 26 +++++++++++++------------- arch/sparc/kernel/sun4d_smp.c | 2 +- arch/sparc/kernel/time_64.c | 2 +- arch/sparc/mm/tlb.c | 4 ++-- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/arch/sparc/include/asm/cpudata_32.h b/arch/sparc/include/asm/cpudata_32.h index 0300d94c25b3..05f366379f53 100644 --- a/arch/sparc/include/asm/cpudata_32.h +++ b/arch/sparc/include/asm/cpudata_32.h @@ -26,6 +26,6 @@ typedef struct { DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); #define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) -#define local_cpu_data() __get_cpu_var(__cpu_data) +#define local_cpu_data() (*this_cpu_ptr(&__cpu_data)) #endif /* _SPARC_CPUDATA_H */ diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h index 0e594076912c..a6e424d185d0 100644 --- a/arch/sparc/include/asm/cpudata_64.h +++ b/arch/sparc/include/asm/cpudata_64.h @@ -30,7 +30,7 @@ typedef struct { DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); #define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) -#define local_cpu_data() __get_cpu_var(__cpu_data) +#define local_cpu_data() (*this_cpu_ptr(&__cpu_data)) #endif /* !(__ASSEMBLY__) */ diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c index 98d712843413..cd83be527586 100644 --- a/arch/sparc/kernel/kprobes.c +++ b/arch/sparc/kernel/kprobes.c @@ -83,7 +83,7 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) { - __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); kcb->kprobe_status = kcb->prev_kprobe.status; kcb->kprobe_orig_tnpc = kcb->prev_kprobe.orig_tnpc; kcb->kprobe_orig_tstate_pil = kcb->prev_kprobe.orig_tstate_pil; @@ -92,7 +92,7 @@ static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { - __get_cpu_var(current_kprobe) = p; + __this_cpu_write(current_kprobe, p); kcb->kprobe_orig_tnpc = regs->tnpc; kcb->kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL); } @@ -155,7 +155,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) ret = 1; goto no_kprobe; } - p = __get_cpu_var(current_kprobe); + p = __this_cpu_read(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) goto ss_probe; } diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c index 018ef11f57df..ea2bad306f93 100644 --- a/arch/sparc/kernel/leon_smp.c +++ b/arch/sparc/kernel/leon_smp.c @@ -343,7 +343,7 @@ static void leon_ipi_resched(int cpu) void leonsmp_ipi_interrupt(void) { - struct leon_ipi_work *work = &__get_cpu_var(leon_ipi_work); + struct leon_ipi_work *work = this_cpu_ptr(&leon_ipi_work); if (work->single) { work->single = 0; diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index 5b1151dcba13..a9973bb4a1b2 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c @@ -100,20 +100,20 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_disable); sum = local_cpu_data().irq0_irqs; - if (__get_cpu_var(nmi_touch)) { - __get_cpu_var(nmi_touch) = 0; + if (__this_cpu_read(nmi_touch)) { + __this_cpu_write(nmi_touch, 0); touched = 1; } - if (!touched && __get_cpu_var(last_irq_sum) == sum) { + if (!touched && __this_cpu_read(last_irq_sum) == sum) { __this_cpu_inc(alert_counter); if (__this_cpu_read(alert_counter) == 30 * nmi_hz) die_nmi("BUG: NMI Watchdog detected LOCKUP", regs, panic_on_timeout); } else { - __get_cpu_var(last_irq_sum) = sum; + __this_cpu_write(last_irq_sum, sum); __this_cpu_write(alert_counter, 0); } - if (__get_cpu_var(wd_enabled)) { + if (__this_cpu_read(wd_enabled)) { pcr_ops->write_pic(0, pcr_ops->nmi_picl_value(nmi_hz)); pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_enable); } @@ -154,7 +154,7 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count) void stop_nmi_watchdog(void *unused) { pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_disable); - __get_cpu_var(wd_enabled) = 0; + __this_cpu_write(wd_enabled, 0); atomic_dec(&nmi_active); } @@ -207,7 +207,7 @@ static int __init check_nmi_watchdog(void) void start_nmi_watchdog(void *unused) { - __get_cpu_var(wd_enabled) = 1; + __this_cpu_write(wd_enabled, 1); atomic_inc(&nmi_active); pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_disable); @@ -218,7 +218,7 @@ void start_nmi_watchdog(void *unused) static void nmi_adjust_hz_one(void *unused) { - if (!__get_cpu_var(wd_enabled)) + if (!__this_cpu_read(wd_enabled)) return; pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_disable); diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index d07f6b29aed8..49d33b178793 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -48,7 +48,7 @@ static int iommu_batch_initialized; /* Interrupts must be disabled. */ static inline void iommu_batch_start(struct device *dev, unsigned long prot, unsigned long entry) { - struct iommu_batch *p = &__get_cpu_var(iommu_batch); + struct iommu_batch *p = this_cpu_ptr(&iommu_batch); p->dev = dev; p->prot = prot; @@ -94,7 +94,7 @@ static long iommu_batch_flush(struct iommu_batch *p) static inline void iommu_batch_new_entry(unsigned long entry) { - struct iommu_batch *p = &__get_cpu_var(iommu_batch); + struct iommu_batch *p = this_cpu_ptr(&iommu_batch); if (p->entry + p->npages == entry) return; @@ -106,7 +106,7 @@ static inline void iommu_batch_new_entry(unsigned long entry) /* Interrupts must be disabled. */ static inline long iommu_batch_add(u64 phys_page) { - struct iommu_batch *p = &__get_cpu_var(iommu_batch); + struct iommu_batch *p = this_cpu_ptr(&iommu_batch); BUG_ON(p->npages >= PGLIST_NENTS); @@ -120,7 +120,7 @@ static inline long iommu_batch_add(u64 phys_page) /* Interrupts must be disabled. */ static inline long iommu_batch_end(void) { - struct iommu_batch *p = &__get_cpu_var(iommu_batch); + struct iommu_batch *p = this_cpu_ptr(&iommu_batch); BUG_ON(p->npages >= PGLIST_NENTS); diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index d35c490a91cb..264049a6cb74 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -1013,7 +1013,7 @@ static void update_pcrs_for_enable(struct cpu_hw_events *cpuc) static void sparc_pmu_enable(struct pmu *pmu) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int i; if (cpuc->enabled) @@ -1031,7 +1031,7 @@ static void sparc_pmu_enable(struct pmu *pmu) static void sparc_pmu_disable(struct pmu *pmu) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int i; if (!cpuc->enabled) @@ -1065,7 +1065,7 @@ static int active_event_index(struct cpu_hw_events *cpuc, static void sparc_pmu_start(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int idx = active_event_index(cpuc, event); if (flags & PERF_EF_RELOAD) { @@ -1080,7 +1080,7 @@ static void sparc_pmu_start(struct perf_event *event, int flags) static void sparc_pmu_stop(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int idx = active_event_index(cpuc, event); if (!(event->hw.state & PERF_HES_STOPPED)) { @@ -1096,7 +1096,7 @@ static void sparc_pmu_stop(struct perf_event *event, int flags) static void sparc_pmu_del(struct perf_event *event, int _flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); unsigned long flags; int i; @@ -1133,7 +1133,7 @@ static void sparc_pmu_del(struct perf_event *event, int _flags) static void sparc_pmu_read(struct perf_event *event) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int idx = active_event_index(cpuc, event); struct hw_perf_event *hwc = &event->hw; @@ -1145,7 +1145,7 @@ static DEFINE_MUTEX(pmc_grab_mutex); static void perf_stop_nmi_watchdog(void *unused) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int i; stop_nmi_watchdog(NULL); @@ -1356,7 +1356,7 @@ static int collect_events(struct perf_event *group, int max_count, static int sparc_pmu_add(struct perf_event *event, int ef_flags) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int n0, ret = -EAGAIN; unsigned long flags; @@ -1498,7 +1498,7 @@ static int sparc_pmu_event_init(struct perf_event *event) */ static void sparc_pmu_start_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); perf_pmu_disable(pmu); cpuhw->group_flag |= PERF_EVENT_TXN; @@ -1511,7 +1511,7 @@ static void sparc_pmu_start_txn(struct pmu *pmu) */ static void sparc_pmu_cancel_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); cpuhw->group_flag &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); @@ -1524,13 +1524,13 @@ static void sparc_pmu_cancel_txn(struct pmu *pmu) */ static int sparc_pmu_commit_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); int n; if (!sparc_pmu) return -EINVAL; - cpuc = &__get_cpu_var(cpu_hw_events); + cpuc = this_cpu_ptr(&cpu_hw_events); n = cpuc->n_events; if (check_excludes(cpuc->event, 0, n)) return -EINVAL; @@ -1601,7 +1601,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self, regs = args->regs; - cpuc = &__get_cpu_var(cpu_hw_events); + cpuc = this_cpu_ptr(&cpu_hw_events); /* If the PMU has the TOE IRQ enable bits, we need to do a * dummy write to the %pcr to clear the overflow bits and thus diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index d5c319553fd0..9d98e5002a09 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -204,7 +204,7 @@ static void __init smp4d_ipi_init(void) void sun4d_ipi_interrupt(void) { - struct sun4d_ipi_work *work = &__get_cpu_var(sun4d_ipi_work); + struct sun4d_ipi_work *work = this_cpu_ptr(&sun4d_ipi_work); if (work->single) { work->single = 0; diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 3fddf64c7fc6..59da0c3ea788 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -765,7 +765,7 @@ void setup_sparc64_timer(void) : /* no outputs */ : "r" (pstate)); - sevt = &__get_cpu_var(sparc64_events); + sevt = this_cpu_ptr(&sparc64_events); memcpy(sevt, &sparc64_clockevent, sizeof(*sevt)); sevt->cpumask = cpumask_of(smp_processor_id()); diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c index b89aba217e3b..9df2190c097e 100644 --- a/arch/sparc/mm/tlb.c +++ b/arch/sparc/mm/tlb.c @@ -52,14 +52,14 @@ void flush_tlb_pending(void) void arch_enter_lazy_mmu_mode(void) { - struct tlb_batch *tb = &__get_cpu_var(tlb_batch); + struct tlb_batch *tb = this_cpu_ptr(&tlb_batch); tb->active = 1; } void arch_leave_lazy_mmu_mode(void) { - struct tlb_batch *tb = &__get_cpu_var(tlb_batch); + struct tlb_batch *tb = this_cpu_ptr(&tlb_batch); if (tb->tlb_nr) flush_tlb_pending(); -- GitLab From 77422a8fee1b96d2420a8a254f784bab8644ac41 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:55 -0500 Subject: [PATCH 0673/5088] clocksource: Replace __this_cpu_ptr with raw_cpu_ptr One newly introduced __this_cpu_ptr should be raw_cpu_ptr. Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- drivers/clocksource/qcom-timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c index 8d115db1e651..098c542e5c53 100644 --- a/drivers/clocksource/qcom-timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -219,7 +219,7 @@ static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, } /* Immediately configure the timer on the boot CPU */ - msm_local_timer_setup(__this_cpu_ptr(msm_evt)); + msm_local_timer_setup(raw_cpu_ptr(msm_evt)); } err: -- GitLab From 47405a253da4d8ca4b18ad537423083fdd790440 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Sun, 17 Aug 2014 12:30:56 -0500 Subject: [PATCH 0674/5088] percpu: Remove __this_cpu_ptr The __this_cpu_ptr macro is no longer in use so drop it. Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- include/linux/percpu-defs.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h index cfd56046ecec..420032d41d27 100644 --- a/include/linux/percpu-defs.h +++ b/include/linux/percpu-defs.h @@ -257,9 +257,6 @@ do { \ #define __raw_get_cpu_var(var) (*raw_cpu_ptr(&(var))) #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) -/* keep until we have removed all uses of __this_cpu_ptr */ -#define __this_cpu_ptr(ptr) raw_cpu_ptr(ptr) - /* * Must be an lvalue. Since @var must be a simple identifier, * we force a syntax error here if it isn't. -- GitLab From eb571eeade2598635f813b3284d02c13a380301e Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Wed, 2 Jul 2014 15:35:16 -0400 Subject: [PATCH 0675/5088] block,scsi: verify return pointer from blk_get_request The blk-core dead queue checks introduce an error scenario to blk_get_request that returns NULL if the request queue has been shutdown. This affects the behavior for __GFP_WAIT callers, who should verify the return value before dereferencing. Signed-off-by: Joe Lawrence Acked-by: Jiri Kosina [for pktdvd] Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe --- block/scsi_ioctl.c | 9 ++++++++- drivers/block/paride/pd.c | 2 ++ drivers/block/pktcdvd.c | 2 ++ drivers/scsi/scsi_error.c | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 51bf5155ee75..29d056782833 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -448,6 +448,10 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, } rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT); + if (!rq) { + err = -ENODEV; + goto error_free_buffer; + } cmdlen = COMMAND_SIZE(opcode); @@ -520,8 +524,9 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, } error: - kfree(buffer); blk_put_request(rq); +error_free_buffer: + kfree(buffer); return err; } EXPORT_SYMBOL_GPL(sg_scsi_ioctl); @@ -534,6 +539,8 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, int err; rq = blk_get_request(q, WRITE, __GFP_WAIT); + if (!rq) + return -ENODEV; blk_rq_set_block_pc(rq); rq->timeout = BLK_DEFAULT_SG_TIMEOUT; rq->cmd[0] = cmd; diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index fea7e76a00de..ca831f741d89 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -722,6 +722,8 @@ static int pd_special_command(struct pd_unit *disk, int err = 0; rq = blk_get_request(disk->gd->queue, READ, __GFP_WAIT); + if (!rq) + return -ENODEV; rq->cmd_type = REQ_TYPE_SPECIAL; rq->special = func; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 758ac442c5b5..7fa8c80e8982 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -704,6 +704,8 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ, __GFP_WAIT); + if (!rq) + return -ENODEV; blk_rq_set_block_pc(rq); if (cgc->buflen) { diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 5db8454474ee..4c433bf47a06 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1960,6 +1960,8 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) * request becomes available */ req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL); + if (!req) + return; blk_rq_set_block_pc(req); -- GitLab From a4f20e2fbc8e84a3aace35af353ca662b455fae1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 15:46:46 -0500 Subject: [PATCH 0676/5088] [media] vpif_display: get rid of some unused vars drivers/media/platform/davinci/vpif_display.c: In function 'vpif_channel_isr': drivers/media/platform/davinci/vpif_display.c:363:18: warning: variable 'field' set but not used [-Wunused-but-set-variable] enum v4l2_field field; ^ drivers/media/platform/davinci/vpif_display.c: In function 'vpif_calculate_offs ets': drivers/media/platform/davinci/vpif_display.c:505:23: warning: variable 'vpitch ' set but not used [-Wunused-but-set-variable] unsigned int hpitch, vpitch, sizeimage; ^ drivers/media/platform/davinci/vpif_display.c: In function 'vpif_set_output': drivers/media/platform/davinci/vpif_display.c:816:27: warning: variable 'subdev _info' set but not used [-Wunused-but-set-variable] struct vpif_subdev_info *subdev_info = NULL; Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_display.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index a03ec7381cfe..aaa9ec06630f 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -360,7 +360,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) struct vpif_device *dev = &vpif_obj; struct channel_obj *ch; struct common_obj *common; - enum v4l2_field field; int fid = -1, i; int channel_id = 0; @@ -369,7 +368,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) return IRQ_NONE; ch = dev->dev[channel_id]; - field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; for (i = 0; i < VPIF_NUMOBJECTS; i++) { common = &ch->common[i]; /* If streaming is started in this channel */ @@ -502,7 +500,7 @@ static void vpif_calculate_offsets(struct channel_obj *ch) struct vpif_params *vpifparams = &ch->vpifparams; enum v4l2_field field = common->fmt.fmt.pix.field; struct video_obj *vid_ch = &ch->video; - unsigned int hpitch, vpitch, sizeimage; + unsigned int hpitch, sizeimage; if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) { if (ch->vpifparams.std_info.frm_fmt) @@ -516,7 +514,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch) sizeimage = common->fmt.fmt.pix.sizeimage; hpitch = common->fmt.fmt.pix.bytesperline; - vpitch = sizeimage / (hpitch * 2); if ((V4L2_FIELD_NONE == vid_ch->buf_field) || (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { common->ytop_off = 0; @@ -813,17 +810,14 @@ static int vpif_set_output(struct vpif_display_config *vpif_cfg, { struct vpif_display_chan_config *chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; - struct vpif_subdev_info *subdev_info = NULL; struct v4l2_subdev *sd = NULL; u32 input = 0, output = 0; int sd_index; int ret; sd_index = vpif_output_to_subdev(vpif_cfg, chan_cfg, index); - if (sd_index >= 0) { + if (sd_index >= 0) sd = vpif_obj.sd[sd_index]; - subdev_info = &vpif_cfg->subdevinfo[sd_index]; - } if (sd) { input = chan_cfg->outputs[index].input_route; -- GitLab From 24ab6338f3fc0f3fe9c541f5e7b29ae026dea0c2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 15:49:06 -0500 Subject: [PATCH 0677/5088] [media] vpif_capture: get rid of some unused vars drivers/media/platform/davinci/vpif_capture.c: In function 'vpif_channel_isr': drivers/media/platform/davinci/vpif_capture.c:376:18: warning: variable 'field' set but not used [-Wunused-but-set-variable] enum v4l2_field field; ^ drivers/media/platform/davinci/vpif_capture.c: In function 'vpif_calculate_offs ets': drivers/media/platform/davinci/vpif_capture.c:536:23: warning: variable 'vpitch ' set but not used [-Wunused-but-set-variable] unsigned int hpitch, vpitch, sizeimage; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_capture.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index b054b7eec53d..cf15bb1962ef 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -373,7 +373,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) struct vpif_device *dev = &vpif_obj; struct common_obj *common; struct channel_obj *ch; - enum v4l2_field field; int channel_id = 0; int fid = -1, i; @@ -383,8 +382,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) ch = dev->dev[channel_id]; - field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; - for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) { common = &ch->common[i]; /* skip If streaming is not started in this channel */ @@ -533,7 +530,7 @@ static int vpif_update_std_info(struct channel_obj *ch) */ static void vpif_calculate_offsets(struct channel_obj *ch) { - unsigned int hpitch, vpitch, sizeimage; + unsigned int hpitch, sizeimage; struct video_obj *vid_ch = &(ch->video); struct vpif_params *vpifparams = &ch->vpifparams; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; @@ -552,7 +549,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch) sizeimage = common->fmt.fmt.pix.sizeimage; hpitch = common->fmt.fmt.pix.bytesperline; - vpitch = sizeimage / (hpitch * 2); if ((V4L2_FIELD_NONE == vid_ch->buf_field) || (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { -- GitLab From f17513c9bf5650738d80cd82f716901b3562bf27 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 15:51:38 -0500 Subject: [PATCH 0678/5088] [media] dm644x_ccdc: declare some functions as static drivers/media/platform/davinci/dm644x_ccdc.c:133:6: warning: no previous protot ype for 'ccdc_setwin' [-Wmissing-prototypes] void ccdc_setwin(struct v4l2_rect *image_win, ^ drivers/media/platform/davinci/dm644x_ccdc.c:373:6: warning: no previous protot ype for 'ccdc_config_ycbcr' [-Wmissing-prototypes] void ccdc_config_ycbcr(void) ^ drivers/media/platform/davinci/dm644x_ccdc.c:526:6: warning: no previous protot ype for 'ccdc_config_raw' [-Wmissing-prototypes] void ccdc_config_raw(void) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm644x_ccdc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index 07e98df3d867..b0b9cd54e9e9 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -130,9 +130,9 @@ static void ccdc_enable_vport(int flag) * This function will configure the window size * to be capture in CCDC reg */ -void ccdc_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, - int ppc) +static void ccdc_setwin(struct v4l2_rect *image_win, + enum ccdc_frmfmt frm_fmt, + int ppc) { int horz_start, horz_nr_pixels; int vert_start, vert_nr_lines; @@ -370,7 +370,7 @@ static int ccdc_set_params(void __user *params) * ccdc_config_ycbcr() * This function will configure CCDC for YCbCr video capture */ -void ccdc_config_ycbcr(void) +static void ccdc_config_ycbcr(void) { struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; u32 syn_mode; @@ -523,7 +523,7 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) * ccdc_config_raw() * This function will configure CCDC for Raw capture mode */ -void ccdc_config_raw(void) +static void ccdc_config_raw(void) { struct ccdc_params_raw *params = &ccdc_cfg.bayer; struct ccdc_config_params_raw *config_params = -- GitLab From 0448056c7e97f3d8aef6777ffc8ed18569f973e3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 15:53:23 -0500 Subject: [PATCH 0679/5088] [media] dm355_ccdc: declare a function as static drivers/media/platform/davinci/dm355_ccdc.c:463:5: warning: no previous prototy pe for 'ccdc_write_dfc_entry' [-Wmissing-prototypes] int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm355_ccdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c index 05f8fb7f7b70..3f44deb5b7a7 100644 --- a/drivers/media/platform/davinci/dm355_ccdc.c +++ b/drivers/media/platform/davinci/dm355_ccdc.c @@ -460,7 +460,7 @@ static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) * ccdc_write_dfc_entry() * write an entry in the dfc table. */ -int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) +static int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) { /* TODO This is to be re-visited and adjusted */ #define DFC_WRITE_WAIT_COUNT 1000 -- GitLab From cff562137226d0f431e85733795edd271e946087 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 15:56:16 -0500 Subject: [PATCH 0680/5088] [media] gsc-core: Remove useless test drivers/media/platform/exynos-gsc/gsc-core.c: In function 'gsc_probe': drivers/media/platform/exynos-gsc/gsc-core.c:1089:2: warning: comparison is alw ays false due to limited range of data type [-Wtype-limits] if (gsc->id < 0 || gsc->id >= drv_data->num_entities) { ^ gsc->id is declared as u16, so it should always be a positive value. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 9d0cc04d7ab7..8d8b3cff8212 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1086,7 +1086,7 @@ static int gsc_probe(struct platform_device *pdev) else gsc->id = pdev->id; - if (gsc->id < 0 || gsc->id >= drv_data->num_entities) { + if (gsc->id >= drv_data->num_entities) { dev_err(dev, "Invalid platform device id: %d\n", gsc->id); return -EINVAL; } -- GitLab From a6a632286865333651fcff3932fea2f945a4d501 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Aug 2014 16:05:39 -0500 Subject: [PATCH 0681/5088] [media] gsc-m2m: Remove an unused var. drivers/media/platform/exynos-gsc/gsc-m2m.c: In function 'gsc_m2m_reqbufs': drivers/media/platform/exynos-gsc/gsc-m2m.c:365:20: warning: variable 'frame' s et but not used [-Wunused-but-set-variable] struct gsc_frame *frame; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-m2m.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index e434f1f03d7b..74e1de637e8f 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -362,7 +362,6 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh, { struct gsc_ctx *ctx = fh_to_ctx(fh); struct gsc_dev *gsc = ctx->gsc_dev; - struct gsc_frame *frame; u32 max_cnt; max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? @@ -376,8 +375,6 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh, gsc_ctx_state_lock_clear(GSC_DST_FMT, ctx); } - frame = ctx_get_frame(ctx, reqbufs->type); - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); } -- GitLab From 78e100cb237389b816ef59ac40f17d2b9b88a930 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 05:41:56 -0500 Subject: [PATCH 0682/5088] [media] ti-vpe: use %pad for dma address drivers/media/platform/ti-vpe/vpdma.c: In function 'dump_dtd': include/linux/dynamic_debug.h:64:16: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'dma_addr_t' [-Wformat=] static struct _ddebug __aligned(8) \ ^ include/linux/dynamic_debug.h:76:2: note: in expansion of macro 'DEFINE_DYNAMIC_DEBUG_METADATA' DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ ^ include/linux/printk.h:263:2: note: in expansion of macro 'dynamic_pr_debug' dynamic_pr_debug(fmt, ##__VA_ARGS__) ^ >> drivers/media/platform/ti-vpe/vpdma.c:587:2: note: in expansion of macro 'pr_debug' pr_debug("word2: start_addr = 0x%08x\n", dtd->start_addr); ^ Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index a51a01359805..6121a0b3c754 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -584,7 +584,7 @@ static void dump_dtd(struct vpdma_dtd *dtd) pr_debug("word1: line_length = %d, xfer_height = %d\n", dtd_get_line_length(dtd), dtd_get_xfer_height(dtd)); - pr_debug("word2: start_addr = 0x%08x\n", dtd->start_addr); + pr_debug("word2: start_addr = %pad\n", &dtd->start_addr); pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, " "pri = %d, next_chan = %d\n", dtd_get_pkt_type(dtd), -- GitLab From 14bb9b0485caa2577925393efc04fab957a38b40 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 05:45:02 -0500 Subject: [PATCH 0683/5088] [media] ti-vpe: shut up a casting warning message drivers/media/platform/ti-vpe/vpdma.c: In function 'vpdma_alloc_desc_buf': >> drivers/media/platform/ti-vpe/vpdma.c:332:10: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] WARN_ON((u32) buf->addr & VPDMA_DESC_ALIGN); ^ Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 6121a0b3c754..684ba19bbedd 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -329,7 +329,7 @@ int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size) if (!buf->addr) return -ENOMEM; - WARN_ON((u32) buf->addr & VPDMA_DESC_ALIGN); + WARN_ON(((u32) buf->addr & VPDMA_DESC_ALIGN) != 0); return 0; } -- GitLab From 8f05232f59ce53f421faf35122bc0e2dd141ea00 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 05:52:54 -0500 Subject: [PATCH 0684/5088] [media] atmel-isi: tag dma_addr_t as such Instead of using u32 for DMA address, use the proper Kernel type for it. drivers/media/platform/soc_camera/atmel-isi.c: In function 'atmel_isi_probe': >> drivers/media/platform/soc_camera/atmel-isi.c:981:26: warning: passing argument 3 of 'dma_alloc_attrs' from incompatible pointer type isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, ^ Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 3408b045b3f1..f87012b15b28 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -54,7 +54,7 @@ static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl) struct isi_dma_desc { struct list_head list; struct fbd *p_fbd; - u32 fbd_phys; + dma_addr_t fbd_phys; }; /* Frame buffer data */ @@ -75,7 +75,7 @@ struct atmel_isi { /* Allocate descriptors for dma buffer use */ struct fbd *p_fb_descriptors; - u32 fb_descriptors_phys; + dma_addr_t fb_descriptors_phys; struct list_head dma_desc_head; struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; @@ -169,7 +169,7 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) isi->active = list_entry(isi->video_buffer_list.next, struct frame_buffer, list); isi_writel(isi, ISI_DMA_C_DSCR, - isi->active->p_dma_desc->fbd_phys); + (u32)isi->active->p_dma_desc->fbd_phys); isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); @@ -346,7 +346,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) return; } - isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_C_DSCR, (u32)buffer->p_dma_desc->fbd_phys); isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); -- GitLab From 9842a417d46bf40f2d460120016b6392d3ac32c9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 05:53:27 -0500 Subject: [PATCH 0685/5088] [media] atmel-isi: Fix a truncate warning drivers/media/platform/soc_camera/atmel-isi.c: In function 'start_streaming': drivers/media/platform/soc_camera/atmel-isi.c:397:26: warning: large integer implicitly truncated to unsigned type [-Woverflow] isi_writel(isi, ISI_INTDIS, ~0UL); ^ Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index f87012b15b28..96a4b112e1ca 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -394,7 +394,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) return ret; } /* Disable all interrupts */ - isi_writel(isi, ISI_INTDIS, ~0UL); + isi_writel(isi, ISI_INTDIS, (u32)~0UL); spin_lock_irq(&isi->lock); /* Clear any pending interrupt */ -- GitLab From 139adba64cdde218e6a679f1d5b675fee937a8d8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 06:07:57 -0500 Subject: [PATCH 0686/5088] [media] s5p_mfc: don't use an external symbol called 'debug' The 'debug' name is known to cause conflicts with allyesconfig on several archs. So, localize its name. >> drivers/built-in.o:(.bss+0xc7ee2c): multiple definition of `debug' arch/x86/built-in.o:(.entry.text+0xf78): first defined here ld: Warning: size of symbol `debug' changed from 86 in arch/x86/built-in.o to 4 in drivers/built-in.o While here, fix a wrong file name reference Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 4 ++-- drivers/media/platform/s5p-mfc/s5p_mfc_debug.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index d35b0418ab37..89b5b4ad34d3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -37,8 +37,8 @@ #define S5P_MFC_DEC_NAME "s5p-mfc-dec" #define S5P_MFC_ENC_NAME "s5p-mfc-enc" -int debug; -module_param(debug, int, S_IRUGO | S_IWUSR); +int mfc_debug_level; +module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages"); /* Helper functions for interrupt processing */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h index 8e608f5aa0d7..5936923c631c 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h @@ -1,5 +1,5 @@ /* - * drivers/media/platform/samsung/mfc5/s5p_mfc_debug.h + * drivers/media/platform/s5p-mfc/s5p_mfc_debug.h * * Header file for Samsung MFC (Multi Function Codec - FIMV) driver * This file contains debug macros @@ -18,11 +18,11 @@ #define DEBUG #ifdef DEBUG -extern int debug; +extern int mfc_debug_level; #define mfc_debug(level, fmt, args...) \ do { \ - if (debug >= level) \ + if (mfc_debug_level >= level) \ printk(KERN_DEBUG "%s:%d: " fmt, \ __func__, __LINE__, ##args); \ } while (0) -- GitLab From 212bdba38724f185344d8ea93f8db0eda1efc348 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 06:38:14 -0500 Subject: [PATCH 0687/5088] [media] vpif: don't cast pointers to int Shut up several warnings about invalid casting when printing the values of two pointers. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 2 +- drivers/media/platform/davinci/vpif_display.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index ea7661a27479..ed9dd27e3c63 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1914,7 +1914,7 @@ static int vpfe_probe(struct platform_device *pdev) v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "trying to register vpfe device.\n"); v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "video_dev=%x\n", (int)&vpfe_dev->video_dev); + "video_dev=%p\n", &vpfe_dev->video_dev); vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = video_register_device(vpfe_dev->video_dev, VFL_TYPE_GRABBER, -1); diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index aaa9ec06630f..2ce3ddfcca80 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1204,8 +1204,8 @@ static int vpif_probe_complete(void) INIT_LIST_HEAD(&common->dma_queue); /* register video device */ - vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", - (int)ch, (int)&ch->video_dev); + vpif_dbg(1, debug, "channel=%p,channel->video_dev=%p\n", + ch, &ch->video_dev); /* Initialize the video_device structure */ vdev = ch->video_dev; -- GitLab From 8dece35daf098e5d086b50724119ffbb24ceca7f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 07:00:42 -0500 Subject: [PATCH 0688/5088] [media] dm644x_ccdc: use unsigned long for fpc_table_addr The fpc_table_addr is used as an unsigned integer that stores an address. At the Kernel, the proper type for such integers is unsigned long. This generates lots of warnings when compiling on 64 bits. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm644x_ccdc.c | 4 ++-- include/media/davinci/dm644x_ccdc.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index b0b9cd54e9e9..62a0ebb01056 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -291,7 +291,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed"); return -EFAULT; } - config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr; + config_params->fault_pxl.fpc_table_addr = (unsigned long)fpc_physaddr; return 0; } @@ -506,7 +506,7 @@ static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) /* Configure Fault pixel if needed */ regw(fpc->fpc_table_addr, CCDC_FPC_ADDR); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n", + dev_dbg(ccdc_cfg.dev, "\nWriting 0x%lx to FPC_ADDR...\n", (fpc->fpc_table_addr)); /* Write the FPC params with FPC disable */ val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK; diff --git a/include/media/davinci/dm644x_ccdc.h b/include/media/davinci/dm644x_ccdc.h index 852e96c4bb46..984fb79031de 100644 --- a/include/media/davinci/dm644x_ccdc.h +++ b/include/media/davinci/dm644x_ccdc.h @@ -114,7 +114,7 @@ struct ccdc_fault_pixel { /* Number of fault pixel */ unsigned short fp_num; /* Address of fault pixel table */ - unsigned int fpc_table_addr; + unsigned long fpc_table_addr; }; /* Structure for CCDC configuration parameters for raw capture mode passed -- GitLab From c623ed63167adcbc16edac22260e1bff150e60df Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 10:30:17 -0500 Subject: [PATCH 0689/5088] [media] dvb_frontend: estimate bandwidth also for DVB-S/S2/Turbo The needed bandwidth can be estimated using the symbol rate and the rolloff factor. This could be useful for the frontend drivers, as they don't need to calculate it themselves. Reported-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index a5810391af61..c862ad732d9e 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2072,6 +2072,23 @@ static int dtv_set_frontend(struct dvb_frontend *fe) case SYS_DVBC_ANNEX_C: rolloff = 113; break; + case SYS_DVBS: + case SYS_TURBO: + rolloff = 135; + break; + case SYS_DVBS2: + switch (c->rolloff) { + case ROLLOFF_20: + rolloff = 120; + break; + case ROLLOFF_25: + rolloff = 125; + break; + default: + case ROLLOFF_35: + rolloff = 135; + } + break; default: break; } -- GitLab From 286da9902240ea8476af6afc02bc29e82508f63f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 10:57:21 -0500 Subject: [PATCH 0690/5088] [media] gsc: Use %pad for dma_addr_t drivers/media/platform/exynos-gsc/gsc-core.c:855:2: note: in expansion of macro 'pr_debug' pr_debug("ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", ^ include/linux/dynamic_debug.h:64:16: warning: format '%X' expects argument of type 'unsigned int', but argument 4 has type 'dma _addr_t' [-Wformat=] static struct _ddebug __aligned(8) \ ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 4 ++-- drivers/media/platform/exynos-gsc/gsc-regs.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 8d8b3cff8212..b4c9f1d08968 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -852,8 +852,8 @@ int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb, (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M)) swap(addr->cb, addr->cr); - pr_debug("ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", - addr->y, addr->cb, addr->cr, ret); + pr_debug("ADDR: y= %pad cb= %pad cr= %pad ret= %d", + &addr->y, &addr->cb, &addr->cr, ret); return ret; } diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c index e22d147a6940..ce12a1100511 100644 --- a/drivers/media/platform/exynos-gsc/gsc-regs.c +++ b/drivers/media/platform/exynos-gsc/gsc-regs.c @@ -90,8 +90,8 @@ void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift, void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr, int index) { - pr_debug("src_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", index, - addr->y, addr->cb, addr->cr); + pr_debug("src_buf[%d]: %pad, cb: %pad, cr: %pad", index, + &addr->y, &addr->cb, &addr->cr); writel(addr->y, dev->regs + GSC_IN_BASE_ADDR_Y(index)); writel(addr->cb, dev->regs + GSC_IN_BASE_ADDR_CB(index)); writel(addr->cr, dev->regs + GSC_IN_BASE_ADDR_CR(index)); @@ -101,8 +101,8 @@ void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr, void gsc_hw_set_output_addr(struct gsc_dev *dev, struct gsc_addr *addr, int index) { - pr_debug("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", - index, addr->y, addr->cb, addr->cr); + pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad", + index, &addr->y, &addr->cb, &addr->cr); writel(addr->y, dev->regs + GSC_OUT_BASE_ADDR_Y(index)); writel(addr->cb, dev->regs + GSC_OUT_BASE_ADDR_CB(index)); writel(addr->cr, dev->regs + GSC_OUT_BASE_ADDR_CR(index)); -- GitLab From 92e3919a49c0ed683ebab8a992eaac331afce8b7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2014 11:11:06 -0500 Subject: [PATCH 0691/5088] [media] omap: fix compilation if !VIDEO_OMAP2_VOUT_VRFB When CONFIG_VIDEO_OMAP2_VOUT_VRFB is disabled, the compilation will fail, as the function stubs are wrong. Also, as they weren't declared as static inline, lots of warnings will be generated. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout_vrfb.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h index ffde741e0590..4c2314839b48 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.h +++ b/drivers/media/platform/omap/omap_vout_vrfb.h @@ -23,18 +23,18 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, struct videobuf_buffer *vb); void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout); #else -void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { } -int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, +static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }; +static inline int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, u32 static_vrfb_allocation) - { return 0; } -void omap_vout_release_vrfb(struct omap_vout_device *vout) { } -int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, + { return 0; }; +static inline void omap_vout_release_vrfb(struct omap_vout_device *vout) { }; +static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, unsigned int *count, unsigned int startindex) - { return 0; } -int omap_vout_prepare_vrfb(struct omap_vout_device *vout, + { return 0; }; +static inline int omap_vout_prepare_vrfb(struct omap_vout_device *vout, struct videobuf_buffer *vb) - { return 0; } -void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { } + { return 0; }; +static inline void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }; #endif #endif -- GitLab From 52334bb3df155e764dd1a9b084115a5a0fa485b6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 10:46:49 -0300 Subject: [PATCH 0692/5088] [media] omap_vout: Get rid of a few warnings drivers/media/platform/omap/omap_vout.c: In function 'omapvid_setup_overlay': drivers/media/platform/omap/omap_vout.c:372:29: warning: variable 'pixheight' set but not used [-Wunused-but-set-variable] int cropheight, cropwidth, pixheight, pixwidth; ^ drivers/media/platform/omap/omap_vout.c: In function 'vidioc_s_ctrl': drivers/media/platform/omap/omap_vout.c:1454:24: warning: variable 'ovl' set but not used [-Wunused-but-set-variable] struct omap_overlay *ovl; ^ drivers/media/platform/omap/omap_vout.c: In function 'vidioc_reqbufs': drivers/media/platform/omap/omap_vout.c:1492:55: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0)) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 2d177fa58471..d9258f3d0f8e 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -369,7 +369,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout, { int ret = 0; struct omap_overlay_info info; - int cropheight, cropwidth, pixheight, pixwidth; + int cropheight, cropwidth, pixwidth; if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 && (outw != vout->pix.width || outh != vout->pix.height)) { @@ -389,12 +389,10 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout, if (is_rotation_90_or_270(vout)) { cropheight = vout->crop.width; cropwidth = vout->crop.height; - pixheight = vout->pix.width; pixwidth = vout->pix.height; } else { cropheight = vout->crop.height; cropwidth = vout->crop.width; - pixheight = vout->pix.height; pixwidth = vout->pix.width; } @@ -1451,12 +1449,10 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) } case V4L2_CID_VFLIP: { - struct omap_overlay *ovl; struct omapvideo_info *ovid; unsigned int mirror = a->value; ovid = &vout->vid_info; - ovl = ovid->overlays[0]; mutex_lock(&vout->lock); if (mirror && ovid->rotation_type == VOUT_ROT_NONE) { @@ -1489,7 +1485,7 @@ static int vidioc_reqbufs(struct file *file, void *fh, struct omap_vout_device *vout = fh; struct videobuf_queue *q = &vout->vbq; - if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0)) + if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; /* if memory is not mmp or userptr return error */ -- GitLab From af425be8b51b02c9bb7bc2fdeb7b4c9ccb25fc5a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 10:50:23 -0300 Subject: [PATCH 0693/5088] [media] s5p-jpeg: get rid of some warnings Declare this as static: drivers/media/platform/s5p-jpeg/jpeg-core.c:732:6: warning: no previous prototype for 'exynos4_jpeg_set_huff_tbl' [-Wmissing-prototypes] void exynos4_jpeg_set_huff_tbl(void __iomem *base) ^ And don't compile this dead code, while not needed: drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c:236:14: warning: no previous prototype for 'exynos3250_jpeg_get_y' [-Wmissing-prototypes] unsigned int exynos3250_jpeg_get_y(void __iomem *regs) ^ drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c:241:14: warning: no previous prototype for 'exynos3250_jpeg_get_x' [-Wmissing-prototypes] unsigned int exynos3250_jpeg_get_x(void __iomem *regs) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-core.c | 2 +- drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index e66acbc2a82d..e525a7c8d885 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -729,7 +729,7 @@ static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality) ARRAY_SIZE(qtbl_chrominance[quality])); } -void exynos4_jpeg_set_huff_tbl(void __iomem *base) +static void exynos4_jpeg_set_huff_tbl(void __iomem *base) { exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL, ARRAY_SIZE(hdctbl0)); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c index d26e1f846553..e8c2cad93962 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c @@ -233,6 +233,7 @@ void exynos3250_jpeg_set_x(void __iomem *regs, unsigned int x) writel(reg, regs + EXYNOS3250_JPGX); } +#if 0 /* Currently unused */ unsigned int exynos3250_jpeg_get_y(void __iomem *regs) { return readl(regs + EXYNOS3250_JPGY); @@ -242,6 +243,7 @@ unsigned int exynos3250_jpeg_get_x(void __iomem *regs) { return readl(regs + EXYNOS3250_JPGX); } +#endif void exynos3250_jpeg_interrupts_enable(void __iomem *regs) { -- GitLab From dc916aa78aec95ce93d9e9e323ba3a5a88b1d516 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 10:52:56 -0300 Subject: [PATCH 0694/5088] [media] g2d: remove unused var drivers/media/platform/s5p-g2d/g2d.c: In function 'job_abort': drivers/media/platform/s5p-g2d/g2d.c:493:6: warning: variable 'ret' set but not used [-Wunused-but-set-variable] int ret; ^ The job_abort function returns void. No sense to get the returned argument, if this won't be used. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-g2d/g2d.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 357af1ebaeda..d79e214ce8ce 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -490,14 +490,13 @@ static void job_abort(void *prv) { struct g2d_ctx *ctx = prv; struct g2d_dev *dev = ctx->dev; - int ret; if (dev->curr == NULL) /* No job currently running */ return; - ret = wait_event_timeout(dev->irq_queue, - dev->curr == NULL, - msecs_to_jiffies(G2D_TIMEOUT)); + wait_event_timeout(dev->irq_queue, + dev->curr == NULL, + msecs_to_jiffies(G2D_TIMEOUT)); } static void device_run(void *prv) -- GitLab From 2ff1d4c13b2881e9276a00bd3032d9afe7d15ef1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 10:56:24 -0300 Subject: [PATCH 0695/5088] [media] fimc-is-param: get rid of warnings In file included from drivers/media/platform/exynos4-is/fimc-is-param.c:31:0: drivers/media/platform/exynos4-is/fimc-is-errno.h:245:20: warning: type qualifiers ignored on function return type [-Wignored-qualifiers] const char * const fimc_is_strerr(unsigned int error); ^ drivers/media/platform/exynos4-is/fimc-is-errno.h:246:20: warning: type qualifiers ignored on function return type [-Wignored-qualifiers] const char * const fimc_is_param_strerr(unsigned int error); ^ drivers/media/platform/exynos4-is/fimc-is-param.c: In function 'fimc_is_set_initial_params': drivers/media/platform/exynos4-is/fimc-is-param.c:670:23: warning: variable 'sensor' set but not used [-Wunused-but-set-variable] struct sensor_param *sensor; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-errno.c | 4 ++-- drivers/media/platform/exynos4-is/fimc-is-errno.h | 4 ++-- drivers/media/platform/exynos4-is/fimc-is-param.c | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.c b/drivers/media/platform/exynos4-is/fimc-is-errno.c index e8519e151c1a..e050e63fe358 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-errno.c +++ b/drivers/media/platform/exynos4-is/fimc-is-errno.c @@ -15,7 +15,7 @@ #include "fimc-is-errno.h" -const char * const fimc_is_param_strerr(unsigned int error) +const char *fimc_is_param_strerr(unsigned int error) { switch (error) { case ERROR_COMMON_CMD: @@ -146,7 +146,7 @@ const char * const fimc_is_param_strerr(unsigned int error) } } -const char * const fimc_is_strerr(unsigned int error) +const char *fimc_is_strerr(unsigned int error) { error &= ~IS_ERROR_TIME_OUT_FLAG; diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.h b/drivers/media/platform/exynos4-is/fimc-is-errno.h index 3de6f6da6f87..ef981e74513a 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-errno.h +++ b/drivers/media/platform/exynos4-is/fimc-is-errno.h @@ -242,7 +242,7 @@ enum fimc_is_error { ERROR_SCALER_FLIP = 521, }; -const char * const fimc_is_strerr(unsigned int error); -const char * const fimc_is_param_strerr(unsigned int error); +const char *fimc_is_strerr(unsigned int error); +const char *fimc_is_param_strerr(unsigned int error); #endif /* FIMC_IS_ERR_H_ */ diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c index bf1465d1bf6d..72b9b436c5c0 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.c +++ b/drivers/media/platform/exynos4-is/fimc-is-param.c @@ -667,7 +667,6 @@ void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val) void fimc_is_set_initial_params(struct fimc_is *is) { struct global_param *global; - struct sensor_param *sensor; struct isp_param *isp; struct drc_param *drc; struct fd_param *fd; @@ -676,7 +675,6 @@ void fimc_is_set_initial_params(struct fimc_is *is) index = is->config_index; global = &is->config[index].global; - sensor = &is->config[index].sensor; isp = &is->config[index].isp; drc = &is->config[index].drc; fd = &is->config[index].fd; -- GitLab From b171e3d8514e80c8e01e59565010b1d7879ac019 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 10:58:23 -0300 Subject: [PATCH 0696/5088] [media] s5p_mfc_ctrl: add missing s5p_mfc_ctrl.h header That gets rid of the following warnings: drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:119:5: warning: no previous prototype for 's5p_mfc_release_firmware' [-Wmissing-prototypes] int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:132:5: warning: no previous prototype for 's5p_mfc_reset' [-Wmissing-prototypes] int s5p_mfc_reset(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:214:5: warning: no previous prototype for 's5p_mfc_init_hw' [-Wmissing-prototypes] int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:291:6: warning: no previous prototype for 's5p_mfc_deinit_hw' [-Wmissing-prototypes] void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:301:5: warning: no previous prototype for 's5p_mfc_sleep' [-Wmissing-prototypes] int s5p_mfc_sleep(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:330:5: warning: no previous prototype for 's5p_mfc_wakeup' [-Wmissing-prototypes] int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:378:5: warning: no previous prototype for 's5p_mfc_open_mfc_inst' [-Wmissing-prototypes] int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) ^ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c:420:6: warning: no previous prototype for 's5p_mfc_close_mfc_inst' [-Wmissing-prototypes] void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index ca9f78922832..5289b8696c1e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -21,6 +21,7 @@ #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" #include "s5p_mfc_pm.h" +#include "s5p_mfc_ctrl.h" /* Allocate memory for firmware */ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) -- GitLab From 8492ec69801ea039546fd27e84fa84f7a0612474 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:13:47 -0300 Subject: [PATCH 0697/5088] [media] s5p_mfc: get rid of several warnings drivers/media/platform/s5p-mfc/s5p_mfc_dec.c:826:5: warning: no previous prototype for 'vidioc_decoder_cmd' [-Wmissing-prototypes] int vidioc_decoder_cmd(struct file *file, void *priv, ^ drivers/media/platform/s5p-mfc/s5p_mfc.c: In function 's5p_mfc_runtime_resume': drivers/media/platform/s5p-mfc/s5p_mfc.c:1314:6: warning: variable 'pre_power' set but not used [-Wunused-but-set-variable] int pre_power; ^ drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c:163:25: warning: no previous prototype for 's5p_mfc_init_hw_cmds_v5' [-Wmissing-prototypes] struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void) ^ drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c:156:25: warning: no previous prototype for 's5p_mfc_init_hw_cmds_v6' [-Wmissing-prototypes] struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void) ^ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c: In function 's5p_mfc_run_dec_frame': drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c:1189:15: warning: variable 'index' set but not used [-Wunused-but-set-variable] unsigned int index; ^ drivers/media/platform/s5p-mfc/s5p_mfc_enc.c: In function 'cleanup_ref_queue': drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:742:27: warning: variable 'mb_c_addr' set but not used [-Wunused-but-set-variable] unsigned long mb_y_addr, mb_c_addr; ^ drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:742:16: warning: variable 'mb_y_addr' set but not used [-Wunused-but-set-variable] unsigned long mb_y_addr, mb_c_addr; ^ drivers/media/platform/s5p-mfc/s5p_mfc_enc.c: At top level: drivers/media/platform/s5p-mfc/s5p_mfc_enc.c:1684:5: warning: no previous prototype for 'vidioc_encoder_cmd' [-Wmissing-prototypes] int vidioc_encoder_cmd(struct file *file, void *priv, ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 -- drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 4 ++-- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 7 ++----- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 2 -- 6 files changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 89b5b4ad34d3..d180440ac43e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1311,11 +1311,9 @@ static int s5p_mfc_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); - int pre_power; if (!m_dev->alloc_ctx) return 0; - pre_power = atomic_read(&m_dev->pm.power); atomic_set(&m_dev->pm.power, 1); return 0; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c index 9a6efd6c1329..8c4739ca16d6 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -14,6 +14,7 @@ #include "s5p_mfc_cmd.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" +#include "s5p_mfc_cmd_v5.h" /* This function is used to send a command to the MFC */ static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c index ec1a5947ed7d..f17609669b96 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -16,6 +16,7 @@ #include "s5p_mfc_debug.h" #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" +#include "s5p_mfc_cmd_v6.h" static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, struct s5p_mfc_cmd_args *args) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 9103258b7df3..fe4d21ccfd49 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -823,8 +823,8 @@ static int vidioc_g_crop(struct file *file, void *priv, return 0; } -int vidioc_decoder_cmd(struct file *file, void *priv, - struct v4l2_decoder_cmd *cmd) +static int vidioc_decoder_cmd(struct file *file, void *priv, + struct v4l2_decoder_cmd *cmd) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); struct s5p_mfc_dev *dev = ctx->dev; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index d26b2484ca10..41f3b7f512fa 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -739,14 +739,11 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_buf *mb_entry; - unsigned long mb_y_addr, mb_c_addr; /* move buffers in ref queue to src queue */ while (!list_empty(&ctx->ref_queue)) { mb_entry = list_entry((&ctx->ref_queue)->next, struct s5p_mfc_buf, list); - mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0); - mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1); list_del(&mb_entry->list); ctx->ref_queue_cnt--; list_add_tail(&mb_entry->list, &ctx->src_queue); @@ -1681,8 +1678,8 @@ static int vidioc_g_parm(struct file *file, void *priv, return 0; } -int vidioc_encoder_cmd(struct file *file, void *priv, - struct v4l2_encoder_cmd *cmd) +static int vidioc_encoder_cmd(struct file *file, void *priv, + struct v4l2_encoder_cmd *cmd) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); struct s5p_mfc_dev *dev = ctx->dev; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 58ec7bb26ebc..31688cddfead 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1186,7 +1186,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *temp_vb; unsigned long flags; - unsigned int index; if (ctx->state == MFCINST_FINISHING) { last_frame = MFC_DEC_LAST_FRAME; @@ -1211,7 +1210,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); - index = temp_vb->b->v4l2_buf.index; dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); if (temp_vb->b->v4l2_planes[0].bytesused == 0) { -- GitLab From 84ddba456e65a26d86c103aa0a4259197aac63fa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:17:16 -0300 Subject: [PATCH 0698/5088] [media] mipi-csis: get rid of a warning drivers/media/platform/exynos4-is/mipi-csis.c: In function 's5pcsis_parse_dt': drivers/media/platform/exynos4-is/mipi-csis.c:756:2: warning: comparison is always false due to limited range of data type [-Wtype-limits] if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/mipi-csis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index ae54ef5f535d..8be8897bc6cd 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -752,7 +752,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, v4l2_of_parse_endpoint(node, &endpoint); state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0; - if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES) + if (state->index >= CSIS_MAX_ENTITIES) return -ENXIO; /* Get MIPI CSI-2 bus configration from the endpoint node. */ -- GitLab From cdf58a6f87a6c941527699c00443d186154f475c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:19:18 -0300 Subject: [PATCH 0699/5088] [media] exynos4-is/media-dev: get rid of a warning for a dead code drivers/media/platform/exynos4-is/media-dev.c: In function 'fimc_md_link_notify': drivers/media/platform/exynos4-is/media-dev.c:1102:4: warning: suggest braces around empty body in an 'else' statement [-Wempty-body] ; /* TODO: Link state change validation */ ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 344718df5c62..54c49d5e7690 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -1098,8 +1098,10 @@ static int fimc_md_link_notify(struct media_link *link, unsigned int flags, if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) { if (!(flags & MEDIA_LNK_FL_ENABLED)) ret = __fimc_md_modify_pipelines(sink, false); +#if 0 else - ; /* TODO: Link state change validation */ + /* TODO: Link state change validation */ +#endif /* After link activation */ } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && (link->flags & MEDIA_LNK_FL_ENABLED)) { -- GitLab From 615f1bcb34317afc615043dd61ba54198f075629 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:20:42 -0300 Subject: [PATCH 0700/5088] [media] mx2_camera: get rid of a warning drivers/media/platform/soc_camera/mx2_camera.c: In function 'mx27_camera_emma_prp_reset': drivers/media/platform/soc_camera/mx2_camera.c:812:6: warning: variable 'cntl' set but not used [-Wunused-but-set-variable] u32 cntl; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/mx2_camera.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index b40bc2e5ba47..2d57c1d272b8 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -809,10 +809,9 @@ static int mx2_camera_init_videobuf(struct vb2_queue *q, static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) { - u32 cntl; int count = 0; - cntl = readl(pcdev->base_emma + PRP_CNTL); + readl(pcdev->base_emma + PRP_CNTL); writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); while (count++ < 100) { if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)) -- GitLab From b91677ad098b7452b03b7a21d195269520f3522d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:21:43 -0300 Subject: [PATCH 0701/5088] [media] atmel-isi: get rid of a warning drivers/media/platform/soc_camera/atmel-isi.c: In function 'start_streaming': drivers/media/platform/soc_camera/atmel-isi.c:387:6: warning: variable 'sr' set but not used [-Wunused-but-set-variable] u32 sr = 0; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 96a4b112e1ca..c5291b001057 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -384,7 +384,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct atmel_isi *isi = ici->priv; - u32 sr = 0; int ret; /* Reset ISI */ @@ -398,7 +397,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) spin_lock_irq(&isi->lock); /* Clear any pending interrupt */ - sr = isi_readl(isi, ISI_STATUS); + isi_readl(isi, ISI_STATUS); if (count) start_dma(isi, isi->active); -- GitLab From c438269948c420518101a836b526f71d389f80dd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 11:23:58 -0300 Subject: [PATCH 0702/5088] [media] s5p-jpeg: Get rid of a warning drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c: In function 's5p_jpeg_clear_int': drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c:327:16: warning: variable 'reg' set but not used [-Wunused-but-set-variable] unsigned long reg; ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c index 52407d790726..0d37bed088df 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c @@ -326,7 +326,7 @@ void s5p_jpeg_clear_int(void __iomem *regs) { unsigned long reg; - reg = readl(regs + S5P_JPGINTST); + readl(regs + S5P_JPGINTST); writel(S5P_INT_RELEASE, regs + S5P_JPGCOM); reg = readl(regs + S5P_JPGOPR); } -- GitLab From 821ee47e0ef589c75c0c10411463c8cd795afafb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 15:04:34 -0300 Subject: [PATCH 0703/5088] Revert "[media] staging: omap4iss: copy paste error in iss_get_clocks" This patch readded a call to iss_put_clocks(), with was removed by changeset 1153be56a105, causing a compilation breakage. This reverts commit d4b32646468088323f27a7788ce3b07191015142. --- drivers/staging/media/omap4iss/iss.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index 8a23d164e847..d548371db65a 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -1014,7 +1014,6 @@ static int iss_get_clocks(struct iss_device *iss) iss->iss_ctrlclk = devm_clk_get(iss->dev, "iss_ctrlclk"); if (IS_ERR(iss->iss_ctrlclk)) { dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n"); - iss_put_clocks(iss); return PTR_ERR(iss->iss_ctrlclk); } -- GitLab From 1c17d8c748b251071c61a4383490881a4071b003 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Aug 2014 13:35:22 -0600 Subject: [PATCH 0704/5088] [media] enable COMPILE_TEST for MX2 eMMa-PrP driver By allowing compilation on all archs, we can use static analysis tools to test this driver. In order to do that, replace asm/sizes.h by its generic name (linux/sizes.h), with should keep doing the right thing. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 3 ++- drivers/media/platform/mx2_emmaprp.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 6d86646d9743..66566c920fe9 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -185,7 +185,8 @@ config VIDEO_SAMSUNG_S5P_MFC config VIDEO_MX2_EMMAPRP tristate "MX2 eMMa-PrP support" - depends on VIDEO_DEV && VIDEO_V4L2 && SOC_IMX27 + depends on VIDEO_DEV && VIDEO_V4L2 + depends on SOC_IMX27 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index fa8f7cabe364..4971ff21f82b 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #define EMMAPRP_MODULE_NAME "mem2mem-emmaprp" -- GitLab From f3334180d4790856bae42fb2e7a3137f9a36aa18 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Aug 2014 13:41:56 -0600 Subject: [PATCH 0705/5088] [media] enable COMPILE_TEST for ti-vbe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allowing COMPILE_TEST here is trivial, but there's one missing header to be added: drivers/media/platform/ti-vpe/vpe.c: In function ‘vpe_probe’: drivers/media/platform/ti-vpe/vpe.c:2266:56: error: ‘SZ_32K’ undeclared (first use in this function) dev->base = devm_ioremap(&pdev->dev, dev->res->start, SZ_32K); ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 3 ++- drivers/media/platform/ti-vpe/vpe.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 66566c920fe9..6d0a0df6d818 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -223,7 +223,8 @@ config VIDEO_RENESAS_VSP1 config VIDEO_TI_VPE tristate "TI VPE (Video Processing Engine) driver" - depends on VIDEO_DEV && VIDEO_V4L2 && SOC_DRA7XX + depends on VIDEO_DEV && VIDEO_V4L2 + depends on SOC_DRA7XX || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 972f43f69206..773b1fbf3269 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include -- GitLab From f2080e38813a3b04d4a6fde5a2697f47cfec4ee5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Aug 2014 13:50:03 -0600 Subject: [PATCH 0706/5088] [media] allow COMPILE_TEST for SAMSUNG_EXYNOS4_IS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That helps some static checks, so enable it. While there, it was noticed that linux/sizes.h was missing: drivers/media/platform/exynos4-is/mipi-csis.c: In function ‘s5pcsis_s_rx_buffer’: drivers/media/platform/exynos4-is/mipi-csis.c:114:31: error: ‘SZ_4K’ undeclared (first use in this function) #define S5PCSIS_PKTDATA_SIZE SZ_4K ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/Kconfig | 2 +- drivers/media/platform/exynos4-is/mipi-csis.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index 5dcaa0a80540..811872195f36 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -2,7 +2,7 @@ config VIDEO_SAMSUNG_EXYNOS4_IS bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on (PLAT_S5P || ARCH_EXYNOS) + depends on (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST) depends on OF && COMMON_CLK help Say Y here to enable camera host interface devices for diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 8be8897bc6cd..db6fd14d1936 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include -- GitLab From 1dbfacf2dd30100ea38181f9cc25feaaa9204630 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Aug 2014 13:56:21 -0600 Subject: [PATCH 0707/5088] [media] enable COMPILE_TEST for OMAP2 vout We don't need anything special to enable COMPILE_TEST for this driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Makefile | 2 +- drivers/media/platform/omap/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 4ac4c91b4415..b598b3bb2645 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -49,6 +49,6 @@ obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ obj-y += davinci/ -obj-$(CONFIG_ARCH_OMAP) += omap/ +obj-y += omap/ ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 37ad446b35b3..2253bf102ed9 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -3,7 +3,7 @@ config VIDEO_OMAP2_VOUT_VRFB config VIDEO_OMAP2_VOUT tristate "OMAP2/OMAP3 V4L2-Display driver" - depends on ARCH_OMAP2 || ARCH_OMAP3 + depends on ARCH_OMAP2 || ARCH_OMAP3 || COMPILE_TEST select VIDEOBUF_GEN select VIDEOBUF_DMA_CONTIG select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS -- GitLab From 7155043c2d027c9c848c3d09badb5af2894ed652 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Aug 2014 13:21:35 -0600 Subject: [PATCH 0708/5088] [media] enable COMPILE_TEST for media drivers There are several arch-specific media drivers that don't require asm-specific includes and can be successfully compiled on x86. Add COMPILE_TEST dependency for them, in order to allow a broader test on those drivers. That helps static analysis tools like Coverity to discover eventual troubles there. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 21 ++++++++++++++------- drivers/media/platform/davinci/Kconfig | 12 ++++++++---- drivers/media/platform/s5p-tv/Kconfig | 3 ++- drivers/media/platform/soc_camera/Kconfig | 10 +++++++--- drivers/media/rc/Kconfig | 5 +++-- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 6d0a0df6d818..a8ae457f8a02 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -56,7 +56,8 @@ config VIDEO_VIU config VIDEO_TIMBERDALE tristate "Support for timberdale Video In/LogiWIN" - depends on MFD_TIMBERDALE && VIDEO_V4L2 && I2C && DMADEVICES + depends on VIDEO_V4L2 && I2C && DMADEVICES + depends on MFD_TIMBERDALE || COMPILE_TEST select DMA_ENGINE select TIMB_DMA select VIDEO_ADV7180 @@ -74,7 +75,8 @@ config VIDEO_VINO config VIDEO_M32R_AR tristate "AR devices" - depends on M32R && VIDEO_V4L2 + depends on VIDEO_V4L2 + depends on M32R || COMPILE_TEST ---help--- This is a video4linux driver for the Renesas AR (Artificial Retina) camera module. @@ -109,7 +111,8 @@ config VIDEO_OMAP3_DEBUG config VIDEO_S3C_CAMIF tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - depends on (ARCH_S3C64XX || PLAT_S3C24XX) && PM_RUNTIME + depends on PM_RUNTIME + depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera @@ -158,7 +161,8 @@ config VIDEO_MEM2MEM_DEINTERLACE config VIDEO_SAMSUNG_S5P_G2D tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" - depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS) + depends on VIDEO_DEV && VIDEO_V4L2 + depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n @@ -168,7 +172,8 @@ config VIDEO_SAMSUNG_S5P_G2D config VIDEO_SAMSUNG_S5P_JPEG tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver" - depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS) + depends on VIDEO_DEV && VIDEO_V4L2 + depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV ---help--- @@ -177,7 +182,8 @@ config VIDEO_SAMSUNG_S5P_JPEG config VIDEO_SAMSUNG_S5P_MFC tristate "Samsung S5P MFC Video Codec" - depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS) + depends on VIDEO_DEV && VIDEO_V4L2 + depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG default n help @@ -196,7 +202,8 @@ config VIDEO_MX2_EMMAPRP config VIDEO_SAMSUNG_EXYNOS_GSC tristate "Samsung Exynos G-Scaler driver" - depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_EXYNOS5 + depends on VIDEO_DEV && VIDEO_V4L2 + depends on ARCH_EXYNOS5 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index afb3aec1320e..35809278e349 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -1,6 +1,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY tristate "TI DaVinci VPIF V4L2-Display driver" - depends on VIDEO_DEV && ARCH_DAVINCI + depends on VIDEO_DEV + depends on ARCH_DAVINCI || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT @@ -14,7 +15,8 @@ config VIDEO_DAVINCI_VPIF_DISPLAY config VIDEO_DAVINCI_VPIF_CAPTURE tristate "TI DaVinci VPIF video capture driver" - depends on VIDEO_DEV && ARCH_DAVINCI + depends on VIDEO_DEV + depends on ARCH_DAVINCI || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPIF module used for capture devices. @@ -26,7 +28,8 @@ config VIDEO_DAVINCI_VPIF_CAPTURE config VIDEO_DM6446_CCDC tristate "TI DM6446 CCDC video capture driver" - depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3) + depends on VIDEO_V4L2 + depends on ARCH_DAVINCI || ARCH_OMAP3 || COMPILE_TEST select VIDEOBUF_DMA_CONTIG help Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces @@ -40,7 +43,8 @@ config VIDEO_DM6446_CCDC config VIDEO_DM355_CCDC tristate "TI DM355 CCDC video capture driver" - depends on VIDEO_V4L2 && ARCH_DAVINCI + depends on VIDEO_V4L2 + depends on ARCH_DAVINCI || COMPILE_TEST select VIDEOBUF_DMA_CONTIG help Enables DM355 CCD hw module. DM355 CCDC hw interfaces diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig index 369a4c191e18..9f38b3dbe0a8 100644 --- a/drivers/media/platform/s5p-tv/Kconfig +++ b/drivers/media/platform/s5p-tv/Kconfig @@ -8,7 +8,8 @@ config VIDEO_SAMSUNG_S5P_TV bool "Samsung TV driver for S5P platform" - depends on (PLAT_S5P || ARCH_EXYNOS) && PM_RUNTIME + depends on PM_RUNTIME + depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST default n ---help--- Say Y here to enable selecting the TV output devices for diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index 6540847f4e1d..c0d4c0f822ea 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig @@ -20,6 +20,7 @@ config SOC_CAMERA_PLATFORM config VIDEO_MX3 tristate "i.MX3x Camera Sensor Interface driver" depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA + depends on MX3_IPU || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the i.MX3x Camera Sensor Interface @@ -58,7 +59,8 @@ config VIDEO_SH_MOBILE_CEU config VIDEO_OMAP1 tristate "OMAP1 Camera Interface driver" - depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA + depends on VIDEO_DEV && SOC_CAMERA + depends on ARCH_OMAP1 || COMPILE_TEST select VIDEOBUF_DMA_CONTIG select VIDEOBUF_DMA_SG ---help--- @@ -66,14 +68,16 @@ config VIDEO_OMAP1 config VIDEO_MX2 tristate "i.MX27 Camera Sensor Interface driver" - depends on VIDEO_DEV && SOC_CAMERA && SOC_IMX27 + depends on VIDEO_DEV && SOC_CAMERA + depends on SOC_IMX27 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the i.MX27 Camera Sensor Interface config VIDEO_ATMEL_ISI tristate "ATMEL Image Sensor Interface (ISI) support" - depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91 + depends on VIDEO_DEV && SOC_CAMERA + depends on ARCH_AT91 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG ---help--- This module makes the ATMEL Image Sensor Interface available diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 5e626af8e313..2b0cc4a98e88 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -333,7 +333,8 @@ config IR_GPIO_CIR config RC_ST tristate "ST remote control receiver" - depends on ARCH_STI && RC_CORE + 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. @@ -344,7 +345,7 @@ config RC_ST config IR_SUNXI tristate "SUNXI IR remote control" depends on RC_CORE - depends on ARCH_SUNXI + depends on ARCH_SUNXI || COMPILE_TEST ---help--- Say Y if you want to use sunXi internal IR Controller -- GitLab From 12bd88e62cf7c1557c7cd78f42a76d7c716b2283 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 16:45:39 -0300 Subject: [PATCH 0709/5088] [media] be sure that HAS_DMA is enabled for vb2-dma-contig vb2-dma-contig depends on HAS_DMA, but the Kbuild doesn't take it into account at select. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/Kconfig | 1 + drivers/media/pci/sta2x11/Kconfig | 1 + drivers/media/platform/Kconfig | 12 ++++++++++++ drivers/media/platform/blackfin/Kconfig | 1 + drivers/media/platform/davinci/Kconfig | 6 ++++++ drivers/media/platform/exynos4-is/Kconfig | 3 +++ drivers/media/platform/marvell-ccic/Kconfig | 2 ++ drivers/media/platform/s5p-tv/Kconfig | 1 + drivers/media/platform/soc_camera/Kconfig | 6 ++++++ drivers/staging/media/davinci_vpfe/Kconfig | 1 + drivers/staging/media/dt3155v4l/Kconfig | 1 + drivers/staging/media/omap4iss/Kconfig | 1 + 12 files changed, 36 insertions(+) diff --git a/drivers/media/pci/solo6x10/Kconfig b/drivers/media/pci/solo6x10/Kconfig index d9e06a6bf1eb..0fb91dc7ca73 100644 --- a/drivers/media/pci/solo6x10/Kconfig +++ b/drivers/media/pci/solo6x10/Kconfig @@ -1,6 +1,7 @@ config VIDEO_SOLO6X10 tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)" depends on PCI && VIDEO_DEV && SND && I2C + depends on HAS_DMA select BITREVERSE select FONT_SUPPORT select FONT_8x16 diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index 03130157db83..f6f30abc088b 100644 --- a/drivers/media/pci/sta2x11/Kconfig +++ b/drivers/media/pci/sta2x11/Kconfig @@ -1,6 +1,7 @@ config STA2X11_VIP tristate "STA2X11 VIP Video For Linux" depends on STA2X11 + depends on HAS_DMA select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT select VIDEOBUF2_DMA_CONTIG depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index a8ae457f8a02..ae021faf7a42 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -96,6 +96,7 @@ config VIDEO_M32R_AR_M64278 config VIDEO_OMAP3 tristate "OMAP 3 Camera support" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 + depends on HAS_DMA select ARM_DMA_USE_IOMMU select OMAP_IOMMU select VIDEOBUF2_DMA_CONTIG @@ -113,6 +114,7 @@ config VIDEO_S3C_CAMIF depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on PM_RUNTIME depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera @@ -143,6 +145,7 @@ if V4L_MEM2MEM_DRIVERS config VIDEO_CODA tristate "Chips&Media Coda multi-standard codec IP" depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MXC + depends on HAS_DMA select SRAM select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV @@ -154,6 +157,7 @@ config VIDEO_CODA config VIDEO_MEM2MEM_DEINTERLACE tristate "Deinterlace support" depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -163,6 +167,7 @@ config VIDEO_SAMSUNG_S5P_G2D tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n @@ -174,6 +179,7 @@ config VIDEO_SAMSUNG_S5P_JPEG tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV ---help--- @@ -184,6 +190,7 @@ config VIDEO_SAMSUNG_S5P_MFC tristate "Samsung S5P MFC Video Codec" depends on VIDEO_DEV && VIDEO_V4L2 depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG default n help @@ -193,6 +200,7 @@ config VIDEO_MX2_EMMAPRP tristate "MX2 eMMa-PrP support" depends on VIDEO_DEV && VIDEO_V4L2 depends on SOC_IMX27 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -204,6 +212,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC tristate "Samsung Exynos G-Scaler driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on ARCH_EXYNOS5 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -212,6 +221,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC config VIDEO_SH_VEU tristate "SuperH VEU mem2mem video processing driver" depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -221,6 +231,7 @@ config VIDEO_SH_VEU config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a V4L2 driver for the Renesas VSP1 video processing engine. @@ -232,6 +243,7 @@ config VIDEO_TI_VPE tristate "TI VPE (Video Processing Engine) driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on SOC_DRA7XX || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n diff --git a/drivers/media/platform/blackfin/Kconfig b/drivers/media/platform/blackfin/Kconfig index cc239972fa2c..68fa90151b8f 100644 --- a/drivers/media/platform/blackfin/Kconfig +++ b/drivers/media/platform/blackfin/Kconfig @@ -1,6 +1,7 @@ config VIDEO_BLACKFIN_CAPTURE tristate "Blackfin Video Capture Driver" depends on VIDEO_V4L2 && BLACKFIN && I2C + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help V4L2 bridge driver for Blackfin video capture device. diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index 35809278e349..b04016e8532d 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -2,6 +2,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY tristate "TI DaVinci VPIF V4L2-Display driver" depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT @@ -17,6 +18,7 @@ config VIDEO_DAVINCI_VPIF_CAPTURE tristate "TI DaVinci VPIF video capture driver" depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPIF module used for capture devices. @@ -30,6 +32,7 @@ config VIDEO_DM6446_CCDC tristate "TI DM6446 CCDC video capture driver" depends on VIDEO_V4L2 depends on ARCH_DAVINCI || ARCH_OMAP3 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG help Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces @@ -45,6 +48,7 @@ config VIDEO_DM355_CCDC tristate "TI DM355 CCDC video capture driver" depends on VIDEO_V4L2 depends on ARCH_DAVINCI || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG help Enables DM355 CCD hw module. DM355 CCDC hw interfaces @@ -59,6 +63,7 @@ config VIDEO_DM355_CCDC config VIDEO_DM365_ISIF tristate "TI DM365 ISIF video capture driver" depends on VIDEO_V4L2 && ARCH_DAVINCI + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG help Enables ISIF hw module. This is the hardware module for @@ -71,6 +76,7 @@ config VIDEO_DM365_ISIF config VIDEO_DAVINCI_VPBE_DISPLAY tristate "TI DaVinci VPBE V4L2-Display driver" depends on ARCH_DAVINCI + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPBE module used for display devices. diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index 811872195f36..77c951237744 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -16,6 +16,7 @@ config VIDEO_EXYNOS4_IS_COMMON config VIDEO_S5P_FIMC tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver" depends on I2C + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select MFD_SYSCON @@ -43,6 +44,7 @@ if SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250 config VIDEO_EXYNOS_FIMC_LITE tristate "EXYNOS FIMC-LITE camera interface driver" depends on I2C + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select VIDEO_EXYNOS4_IS_COMMON help @@ -55,6 +57,7 @@ endif config VIDEO_EXYNOS4_FIMC_IS tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver" + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG depends on OF select FW_LOADER diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig index bf739e3b3398..6265d36adceb 100644 --- a/drivers/media/platform/marvell-ccic/Kconfig +++ b/drivers/media/platform/marvell-ccic/Kconfig @@ -1,6 +1,7 @@ config VIDEO_CAFE_CCIC tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" depends on PCI && I2C && VIDEO_V4L2 + depends on HAS_DMA select VIDEO_OV7670 select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG @@ -12,6 +13,7 @@ config VIDEO_CAFE_CCIC config VIDEO_MMP_CAMERA tristate "Marvell Armada 610 integrated camera controller support" depends on ARCH_MMP && I2C && VIDEO_V4L2 + depends on HAS_DMA select VIDEO_OV7670 select I2C_GPIO select VIDEOBUF2_DMA_SG diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig index 9f38b3dbe0a8..a9d56f8936b4 100644 --- a/drivers/media/platform/s5p-tv/Kconfig +++ b/drivers/media/platform/s5p-tv/Kconfig @@ -71,6 +71,7 @@ config VIDEO_SAMSUNG_S5P_MIXER tristate "Samsung Mixer and Video Processor Driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on VIDEO_SAMSUNG_S5P_TV + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Say Y here if you want support for the Mixer in Samsung S5P SoCs. diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index c0d4c0f822ea..6af6c6dccda8 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig @@ -21,6 +21,7 @@ config VIDEO_MX3 tristate "i.MX3x Camera Sensor Interface driver" depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA depends on MX3_IPU || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the i.MX3x Camera Sensor Interface @@ -36,6 +37,7 @@ config VIDEO_RCAR_VIN tristate "R-Car Video Input (VIN) support" depends on VIDEO_DEV && SOC_CAMERA depends on ARCH_SHMOBILE || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select SOC_CAMERA_SCALE_CROP ---help--- @@ -52,6 +54,7 @@ config VIDEO_SH_MOBILE_CEU tristate "SuperH Mobile CEU Interface driver" depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select SOC_CAMERA_SCALE_CROP ---help--- @@ -61,6 +64,7 @@ config VIDEO_OMAP1 tristate "OMAP1 Camera Interface driver" depends on VIDEO_DEV && SOC_CAMERA depends on ARCH_OMAP1 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG select VIDEOBUF_DMA_SG ---help--- @@ -70,6 +74,7 @@ config VIDEO_MX2 tristate "i.MX27 Camera Sensor Interface driver" depends on VIDEO_DEV && SOC_CAMERA depends on SOC_IMX27 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the i.MX27 Camera Sensor Interface @@ -78,6 +83,7 @@ config VIDEO_ATMEL_ISI tristate "ATMEL Image Sensor Interface (ISI) support" depends on VIDEO_DEV && SOC_CAMERA depends on ARCH_AT91 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This module makes the ATMEL Image Sensor Interface available diff --git a/drivers/staging/media/davinci_vpfe/Kconfig b/drivers/staging/media/davinci_vpfe/Kconfig index 12f321dd2399..4de2f082491d 100644 --- a/drivers/staging/media/davinci_vpfe/Kconfig +++ b/drivers/staging/media/davinci_vpfe/Kconfig @@ -1,6 +1,7 @@ config VIDEO_DM365_VPFE tristate "DM365 VPFE Media Controller Capture Driver" depends on VIDEO_V4L2 && ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Support for DM365 VPFE based Media Controller Capture driver. diff --git a/drivers/staging/media/dt3155v4l/Kconfig b/drivers/staging/media/dt3155v4l/Kconfig index 226a1ca90b3c..2d496001b6e8 100644 --- a/drivers/staging/media/dt3155v4l/Kconfig +++ b/drivers/staging/media/dt3155v4l/Kconfig @@ -1,6 +1,7 @@ config VIDEO_DT3155 tristate "DT3155 frame grabber, Video4Linux interface" depends on PCI && VIDEO_DEV && VIDEO_V4L2 + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG default n ---help--- diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig index 8afc6fee40c5..b78643f907e7 100644 --- a/drivers/staging/media/omap4iss/Kconfig +++ b/drivers/staging/media/omap4iss/Kconfig @@ -1,6 +1,7 @@ config VIDEO_OMAP4 bool "OMAP 4 Camera support" depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4 + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- Driver for an OMAP 4 ISS controller. -- GitLab From 38a0731165250a0a77eff7b90ea3156d44cc7d66 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 16:51:56 -0300 Subject: [PATCH 0710/5088] [media] omap: be sure that MMU is there for COMPILE_TEST COMPILE_TEST fail on (some) archs without MMU. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 2253bf102ed9..05de442d24e4 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -3,7 +3,7 @@ config VIDEO_OMAP2_VOUT_VRFB config VIDEO_OMAP2_VOUT tristate "OMAP2/OMAP3 V4L2-Display driver" - depends on ARCH_OMAP2 || ARCH_OMAP3 || COMPILE_TEST + depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && HAS_MMU) select VIDEOBUF_GEN select VIDEOBUF_DMA_CONTIG select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS -- GitLab From 890b13a308b9df78ad05fc57eb440b32399be35e Mon Sep 17 00:00:00 2001 From: Konstantinos Tsimpoukas Date: Tue, 26 Aug 2014 23:21:48 -0500 Subject: [PATCH 0711/5088] ALSA: ice1712: Replacing hex with #defines Adds to the readability of the ice1712 driver. Signed-off-by: Konstantinos Tsimpoukas Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 87f7fc41d4f2..206ed2cbcef9 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2528,7 +2528,7 @@ static int snd_ice1712_free(struct snd_ice1712 *ice) if (!ice->port) goto __hw_end; /* mask all interrupts */ - outb(0xc0, ICEMT(ice, IRQ)); + outb(ICE1712_MULTI_CAPTURE | ICE1712_MULTI_PLAYBACK, ICEMT(ice, IRQ)); outb(0xff, ICEREG(ice, IRQMASK)); /* --- */ __hw_end: -- GitLab From 88299c9bdb109e0d95abdca648065631ff91b2cb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 1 Aug 2014 11:28:48 +0300 Subject: [PATCH 0712/5088] timerfd: Remove an always true check We would have returned -EINVAL earlier if ticks wasn't set. Signed-off-by: Dan Carpenter Cc: Alexander Viro Cc: Cyrill Gorcunov Link: http://lkml.kernel.org/r/20140801082848.GF28869@mwanda Signed-off-by: Thomas Gleixner --- fs/timerfd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/timerfd.c b/fs/timerfd.c index 80c350216ea8..b46ffa94372a 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c @@ -333,8 +333,7 @@ static long timerfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg spin_lock_irq(&ctx->wqh.lock); if (!timerfd_canceled(ctx)) { ctx->ticks = ticks; - if (ticks) - wake_up_locked(&ctx->wqh); + wake_up_locked(&ctx->wqh); } else ret = -ECANCELED; spin_unlock_irq(&ctx->wqh.lock); -- GitLab From f1217ed09f827e42a49ffa6a5aab672aa6f57a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 27 Aug 2014 13:16:04 +0200 Subject: [PATCH 0713/5088] drm/ttm: move fpfn and lpfn into each placement v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to more fine grained specify where to place the buffer object. v2: rebased on drm-next, add bochs changes as well Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/ast/ast_drv.h | 2 +- drivers/gpu/drm/ast/ast_ttm.c | 20 +-- drivers/gpu/drm/bochs/bochs.h | 2 +- drivers/gpu/drm/bochs/bochs_mm.c | 20 ++- drivers/gpu/drm/cirrus/cirrus_drv.h | 2 +- drivers/gpu/drm/cirrus/cirrus_ttm.c | 17 ++- drivers/gpu/drm/mgag200/mgag200_drv.h | 2 +- drivers/gpu/drm/mgag200/mgag200_ttm.c | 20 +-- drivers/gpu/drm/nouveau/nouveau_bo.c | 52 +++++-- drivers/gpu/drm/nouveau/nouveau_bo.h | 4 +- drivers/gpu/drm/nouveau/nouveau_ttm.c | 9 +- drivers/gpu/drm/qxl/qxl_drv.h | 2 +- drivers/gpu/drm/qxl/qxl_object.c | 17 ++- drivers/gpu/drm/qxl/qxl_ttm.c | 8 +- drivers/gpu/drm/radeon/radeon.h | 2 +- drivers/gpu/drm/radeon/radeon_object.c | 71 +++++---- drivers/gpu/drm/radeon/radeon_ttm.c | 25 ++-- drivers/gpu/drm/radeon/radeon_uvd.c | 8 +- drivers/gpu/drm/ttm/ttm_bo.c | 93 +++++------- drivers/gpu/drm/ttm/ttm_bo_manager.c | 9 +- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 136 +++++++++++------- drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c | 22 ++- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 10 +- drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c | 3 +- include/drm/ttm/ttm_bo_api.h | 40 +++--- include/drm/ttm/ttm_bo_driver.h | 3 +- 26 files changed, 346 insertions(+), 253 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 957d4fabf1e1..cb91c2acc3cb 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -316,7 +316,7 @@ struct ast_bo { struct ttm_placement placement; struct ttm_bo_kmap_obj kmap; struct drm_gem_object gem; - u32 placements[3]; + struct ttm_place placements[3]; int pin_count; }; #define gem_to_ast_bo(gobj) container_of((gobj), struct ast_bo, gem) diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index b8246227bab0..8008ea0bc76c 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -293,18 +293,22 @@ void ast_mm_fini(struct ast_private *ast) void ast_ttm_placement(struct ast_bo *bo, int domain) { u32 c = 0; - bo->placement.fpfn = 0; - bo->placement.lpfn = 0; + unsigned i; + bo->placement.placement = bo->placements; bo->placement.busy_placement = bo->placements; if (domain & TTM_PL_FLAG_VRAM) - bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; + bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; if (domain & TTM_PL_FLAG_SYSTEM) - bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; if (!c) - bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; bo->placement.num_placement = c; bo->placement.num_busy_placement = c; + for (i = 0; i < c; ++i) { + bo->placements[i].fpfn = 0; + bo->placements[i].lpfn = 0; + } } int ast_bo_create(struct drm_device *dev, int size, int align, @@ -360,7 +364,7 @@ int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr) ast_ttm_placement(bo, pl_flag); for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); if (ret) return ret; @@ -383,7 +387,7 @@ int ast_bo_unpin(struct ast_bo *bo) return 0; for (i = 0; i < bo->placement.num_placement ; i++) - bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); if (ret) return ret; @@ -407,7 +411,7 @@ int ast_bo_push_sysram(struct ast_bo *bo) ast_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); for (i = 0; i < bo->placement.num_placement ; i++) - bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); if (ret) { diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h index 7eb52dd44b01..4f6e7b3a3635 100644 --- a/drivers/gpu/drm/bochs/bochs.h +++ b/drivers/gpu/drm/bochs/bochs.h @@ -99,7 +99,7 @@ struct bochs_bo { struct ttm_placement placement; struct ttm_bo_kmap_obj kmap; struct drm_gem_object gem; - u32 placements[3]; + struct ttm_place placements[3]; int pin_count; }; diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 1728a1b0b813..2af30e7607d7 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -257,20 +257,26 @@ void bochs_mm_fini(struct bochs_device *bochs) static void bochs_ttm_placement(struct bochs_bo *bo, int domain) { + unsigned i; u32 c = 0; - bo->placement.fpfn = 0; - bo->placement.lpfn = 0; bo->placement.placement = bo->placements; bo->placement.busy_placement = bo->placements; if (domain & TTM_PL_FLAG_VRAM) { - bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED + bo->placements[c++].flags = TTM_PL_FLAG_WC + | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; } if (domain & TTM_PL_FLAG_SYSTEM) { - bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + bo->placements[c++].flags = TTM_PL_MASK_CACHING + | TTM_PL_FLAG_SYSTEM; } if (!c) { - bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + bo->placements[c++].flags = TTM_PL_MASK_CACHING + | TTM_PL_FLAG_SYSTEM; + } + for (i = 0; i < c; ++i) { + bo->placements[i].fpfn = 0; + bo->placements[i].lpfn = 0; } bo->placement.num_placement = c; bo->placement.num_busy_placement = c; @@ -294,7 +300,7 @@ int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr) bochs_ttm_placement(bo, pl_flag); for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); if (ret) return ret; @@ -319,7 +325,7 @@ int bochs_bo_unpin(struct bochs_bo *bo) return 0; for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); if (ret) return ret; diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index 401c890b6c6a..dd2cfc9024aa 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -163,7 +163,7 @@ struct cirrus_bo { struct ttm_placement placement; struct ttm_bo_kmap_obj kmap; struct drm_gem_object gem; - u32 placements[3]; + struct ttm_place placements[3]; int pin_count; }; #define gem_to_cirrus_bo(gobj) container_of((gobj), struct cirrus_bo, gem) diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 92e6b7786097..3e7d758330a9 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -298,18 +298,21 @@ void cirrus_mm_fini(struct cirrus_device *cirrus) void cirrus_ttm_placement(struct cirrus_bo *bo, int domain) { u32 c = 0; - bo->placement.fpfn = 0; - bo->placement.lpfn = 0; + unsigned i; bo->placement.placement = bo->placements; bo->placement.busy_placement = bo->placements; if (domain & TTM_PL_FLAG_VRAM) - bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; + bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; if (domain & TTM_PL_FLAG_SYSTEM) - bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; if (!c) - bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; bo->placement.num_placement = c; bo->placement.num_busy_placement = c; + for (i = 0; i < c; ++i) { + bo->placements[i].fpfn = 0; + bo->placements[i].lpfn = 0; + } } int cirrus_bo_create(struct drm_device *dev, int size, int align, @@ -365,7 +368,7 @@ int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr) cirrus_ttm_placement(bo, pl_flag); for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); if (ret) return ret; @@ -392,7 +395,7 @@ int cirrus_bo_push_sysram(struct cirrus_bo *bo) cirrus_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); for (i = 0; i < bo->placement.num_placement ; i++) - bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); if (ret) { diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 80de23d9b9c9..2e2b76aa4e17 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -224,7 +224,7 @@ struct mgag200_bo { struct ttm_placement placement; struct ttm_bo_kmap_obj kmap; struct drm_gem_object gem; - u32 placements[3]; + struct ttm_place placements[3]; int pin_count; }; #define gem_to_mga_bo(gobj) container_of((gobj), struct mgag200_bo, gem) diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 5a00e90696de..be883ef5a1d3 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -293,18 +293,22 @@ void mgag200_mm_fini(struct mga_device *mdev) void mgag200_ttm_placement(struct mgag200_bo *bo, int domain) { u32 c = 0; - bo->placement.fpfn = 0; - bo->placement.lpfn = 0; + unsigned i; + bo->placement.placement = bo->placements; bo->placement.busy_placement = bo->placements; if (domain & TTM_PL_FLAG_VRAM) - bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; + bo->placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; if (domain & TTM_PL_FLAG_SYSTEM) - bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; if (!c) - bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + bo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; bo->placement.num_placement = c; bo->placement.num_busy_placement = c; + for (i = 0; i < c; ++i) { + bo->placements[i].fpfn = 0; + bo->placements[i].lpfn = 0; + } } int mgag200_bo_create(struct drm_device *dev, int size, int align, @@ -361,7 +365,7 @@ int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr) mgag200_ttm_placement(bo, pl_flag); for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); if (ret) return ret; @@ -384,7 +388,7 @@ int mgag200_bo_unpin(struct mgag200_bo *bo) return 0; for (i = 0; i < bo->placement.num_placement ; i++) - bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); if (ret) return ret; @@ -408,7 +412,7 @@ int mgag200_bo_push_sysram(struct mgag200_bo *bo) mgag200_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); for (i = 0; i < bo->placement.num_placement ; i++) - bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 01da508625f2..0591ca0734e3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -241,16 +241,16 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, } static void -set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags) +set_placement_list(struct ttm_place *pl, unsigned *n, uint32_t type, uint32_t flags) { *n = 0; if (type & TTM_PL_FLAG_VRAM) - pl[(*n)++] = TTM_PL_FLAG_VRAM | flags; + pl[(*n)++].flags = TTM_PL_FLAG_VRAM | flags; if (type & TTM_PL_FLAG_TT) - pl[(*n)++] = TTM_PL_FLAG_TT | flags; + pl[(*n)++].flags = TTM_PL_FLAG_TT | flags; if (type & TTM_PL_FLAG_SYSTEM) - pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags; + pl[(*n)++].flags = TTM_PL_FLAG_SYSTEM | flags; } static void @@ -258,6 +258,7 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type) { struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); u32 vram_pages = drm->device.info.ram_size >> PAGE_SHIFT; + unsigned i, fpfn, lpfn; if (drm->device.info.family == NV_DEVICE_INFO_V0_CELSIUS && nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) && @@ -269,11 +270,19 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type) * at the same time. */ if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) { - nvbo->placement.fpfn = vram_pages / 2; - nvbo->placement.lpfn = ~0; + fpfn = vram_pages / 2; + lpfn = ~0; } else { - nvbo->placement.fpfn = 0; - nvbo->placement.lpfn = vram_pages / 2; + fpfn = 0; + lpfn = vram_pages / 2; + } + for (i = 0; i < nvbo->placement.num_placement; ++i) { + nvbo->placements[i].fpfn = fpfn; + nvbo->placements[i].lpfn = lpfn; + } + for (i = 0; i < nvbo->placement.num_busy_placement; ++i) { + nvbo->busy_placements[i].fpfn = fpfn; + nvbo->busy_placements[i].lpfn = lpfn; } } } @@ -1041,12 +1050,15 @@ static int nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, bool no_wait_gpu, struct ttm_mem_reg *new_mem) { - u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; + struct ttm_place placement_memtype = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING + }; struct ttm_placement placement; struct ttm_mem_reg tmp_mem; int ret; - placement.fpfn = placement.lpfn = 0; placement.num_placement = placement.num_busy_placement = 1; placement.placement = placement.busy_placement = &placement_memtype; @@ -1074,12 +1086,15 @@ static int nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, bool no_wait_gpu, struct ttm_mem_reg *new_mem) { - u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; + struct ttm_place placement_memtype = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING + }; struct ttm_placement placement; struct ttm_mem_reg tmp_mem; int ret; - placement.fpfn = placement.lpfn = 0; placement.num_placement = placement.num_busy_placement = 1; placement.placement = placement.busy_placement = &placement_memtype; @@ -1294,7 +1309,7 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) struct nouveau_bo *nvbo = nouveau_bo(bo); struct nvif_device *device = &drm->device; u32 mappable = nv_device_resource_len(nvkm_device(device), 1) >> PAGE_SHIFT; - int ret; + int i, ret; /* as long as the bo isn't in vram, and isn't tiled, we've got * nothing to do here. @@ -1319,9 +1334,16 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) bo->mem.start + bo->mem.num_pages < mappable) return 0; + for (i = 0; i < nvbo->placement.num_placement; ++i) { + nvbo->placements[i].fpfn = 0; + nvbo->placements[i].lpfn = mappable; + } + + for (i = 0; i < nvbo->placement.num_busy_placement; ++i) { + nvbo->busy_placements[i].fpfn = 0; + nvbo->busy_placements[i].lpfn = mappable; + } - nvbo->placement.fpfn = 0; - nvbo->placement.lpfn = mappable; nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_VRAM, 0); return nouveau_bo_validate(nvbo, false, false); } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index ff17c1f432fc..4ef88e84a694 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -9,8 +9,8 @@ struct nouveau_bo { struct ttm_buffer_object bo; struct ttm_placement placement; u32 valid_domains; - u32 placements[3]; - u32 busy_placements[3]; + struct ttm_place placements[3]; + struct ttm_place busy_placements[3]; struct ttm_bo_kmap_obj kmap; struct list_head head; diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 53874b76b031..e81d086577ce 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -71,8 +71,7 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man, static int nouveau_vram_manager_new(struct ttm_mem_type_manager *man, struct ttm_buffer_object *bo, - struct ttm_placement *placement, - uint32_t flags, + const struct ttm_place *place, struct ttm_mem_reg *mem) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); @@ -158,8 +157,7 @@ nouveau_gart_manager_del(struct ttm_mem_type_manager *man, static int nouveau_gart_manager_new(struct ttm_mem_type_manager *man, struct ttm_buffer_object *bo, - struct ttm_placement *placement, - uint32_t flags, + const struct ttm_place *place, struct ttm_mem_reg *mem) { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); @@ -239,8 +237,7 @@ nv04_gart_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem) static int nv04_gart_manager_new(struct ttm_mem_type_manager *man, struct ttm_buffer_object *bo, - struct ttm_placement *placement, - uint32_t flags, + const struct ttm_place *place, struct ttm_mem_reg *mem) { struct nouveau_mem *node; diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 36ed40ba773f..f6022b703645 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -106,7 +106,7 @@ struct qxl_bo { /* Protected by gem.mutex */ struct list_head list; /* Protected by tbo.reserved */ - u32 placements[3]; + struct ttm_place placements[3]; struct ttm_placement placement; struct ttm_buffer_object tbo; struct ttm_bo_kmap_obj kmap; diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index b95f144f0b49..adad12d30372 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -55,21 +55,24 @@ void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain, bool pinned) { u32 c = 0; u32 pflag = pinned ? TTM_PL_FLAG_NO_EVICT : 0; + unsigned i; - qbo->placement.fpfn = 0; - qbo->placement.lpfn = 0; qbo->placement.placement = qbo->placements; qbo->placement.busy_placement = qbo->placements; if (domain == QXL_GEM_DOMAIN_VRAM) - qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag; + qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_VRAM | pflag; if (domain == QXL_GEM_DOMAIN_SURFACE) - qbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0 | pflag; + qbo->placements[c++].flags = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_PRIV0 | pflag; if (domain == QXL_GEM_DOMAIN_CPU) - qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM | pflag; + qbo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM | pflag; if (!c) - qbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + qbo->placements[c++].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; qbo->placement.num_placement = c; qbo->placement.num_busy_placement = c; + for (i = 0; i < c; ++i) { + qbo->placements[i].fpfn = 0; + qbo->placements[i].lpfn = 0; + } } @@ -259,7 +262,7 @@ int qxl_bo_unpin(struct qxl_bo *bo) if (bo->pin_count) return 0; for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; + bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); if (unlikely(r != 0)) dev_err(qdev->dev, "%p validate failed for unpin\n", bo); diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 71a1baeac14e..f66c59b222f1 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -188,11 +188,13 @@ static void qxl_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *placement) { struct qxl_bo *qbo; - static u32 placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + static struct ttm_place placements = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM + }; if (!qxl_ttm_bo_is_qxl_bo(bo)) { - placement->fpfn = 0; - placement->lpfn = 0; placement->placement = &placements; placement->busy_placement = &placements; placement->num_placement = 1; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b321ad4dcafd..bb01dab513dd 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -469,7 +469,7 @@ struct radeon_bo { struct list_head list; /* Protected by tbo.reserved */ u32 initial_domain; - u32 placements[3]; + struct ttm_place placements[3]; struct ttm_placement placement; struct ttm_buffer_object tbo; struct ttm_bo_kmap_obj kmap; diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 287523807989..0129c7efae3b 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -97,40 +97,56 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) { u32 c = 0, i; - rbo->placement.fpfn = 0; - rbo->placement.lpfn = 0; rbo->placement.placement = rbo->placements; rbo->placement.busy_placement = rbo->placements; if (domain & RADEON_GEM_DOMAIN_VRAM) - rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | - TTM_PL_FLAG_VRAM; + rbo->placements[c++].flags = TTM_PL_FLAG_WC | + TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_VRAM; + if (domain & RADEON_GEM_DOMAIN_GTT) { if (rbo->flags & RADEON_GEM_GTT_UC) { - rbo->placements[c++] = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_TT; + rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_TT; + } else if ((rbo->flags & RADEON_GEM_GTT_WC) || (rbo->rdev->flags & RADEON_IS_AGP)) { - rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | + rbo->placements[c++].flags = TTM_PL_FLAG_WC | + TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_TT; } else { - rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT; + rbo->placements[c++].flags = TTM_PL_FLAG_CACHED | + TTM_PL_FLAG_TT; } } + if (domain & RADEON_GEM_DOMAIN_CPU) { if (rbo->flags & RADEON_GEM_GTT_UC) { - rbo->placements[c++] = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_SYSTEM; + rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_SYSTEM; + } else if ((rbo->flags & RADEON_GEM_GTT_WC) || rbo->rdev->flags & RADEON_IS_AGP) { - rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | + rbo->placements[c++].flags = TTM_PL_FLAG_WC | + TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_SYSTEM; } else { - rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM; + rbo->placements[c++].flags = TTM_PL_FLAG_CACHED | + TTM_PL_FLAG_SYSTEM; } } if (!c) - rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + rbo->placements[c++].flags = TTM_PL_MASK_CACHING | + TTM_PL_FLAG_SYSTEM; + rbo->placement.num_placement = c; rbo->placement.num_busy_placement = c; + for (i = 0; i < c; ++i) { + rbo->placements[i].fpfn = 0; + rbo->placements[i].lpfn = 0; + } + /* * Use two-ended allocation depending on the buffer size to * improve fragmentation quality. @@ -138,7 +154,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) */ if (rbo->tbo.mem.size > 512 * 1024) { for (i = 0; i < c; i++) { - rbo->placements[i] |= TTM_PL_FLAG_TOPDOWN; + rbo->placements[i].flags |= TTM_PL_FLAG_TOPDOWN; } } } @@ -287,21 +303,22 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset, return 0; } radeon_ttm_placement_from_domain(bo, domain); - if (domain == RADEON_GEM_DOMAIN_VRAM) { + for (i = 0; i < bo->placement.num_placement; i++) { + unsigned lpfn = 0; + /* force to pin into visible video ram */ - bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT; - } - if (max_offset) { - u64 lpfn = max_offset >> PAGE_SHIFT; + if (bo->placements[i].flags & TTM_PL_FLAG_VRAM) + lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT; + else + lpfn = bo->rdev->mc.gtt_size >> PAGE_SHIFT; /* ??? */ - if (!bo->placement.lpfn) - bo->placement.lpfn = bo->rdev->mc.gtt_size >> PAGE_SHIFT; + if (max_offset) + lpfn = min (lpfn, (unsigned)(max_offset >> PAGE_SHIFT)); - if (lpfn < bo->placement.lpfn) - bo->placement.lpfn = lpfn; + bo->placements[i].lpfn = lpfn; + bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; } - for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); if (likely(r == 0)) { bo->pin_count = 1; @@ -333,8 +350,10 @@ int radeon_bo_unpin(struct radeon_bo *bo) bo->pin_count--; if (bo->pin_count) return 0; - for (i = 0; i < bo->placement.num_placement; i++) - bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; + for (i = 0; i < bo->placement.num_placement; i++) { + bo->placements[i].lpfn = 0; + bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; + } r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); if (likely(r == 0)) { if (bo->tbo.mem.mem_type == TTM_PL_VRAM) @@ -735,7 +754,7 @@ int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo) /* hurrah the memory is not visible ! */ radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM); - rbo->placement.lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; + rbo->placements[0].lpfn = rdev->mc.visible_vram_size >> PAGE_SHIFT; r = ttm_bo_validate(bo, &rbo->placement, false, false); if (unlikely(r == -ENOMEM)) { radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 12e37b1ddc40..822eb3630045 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -178,12 +178,15 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, static void radeon_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *placement) { + static struct ttm_place placements = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM + }; + struct radeon_bo *rbo; - static u32 placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; if (!radeon_ttm_bo_is_radeon_bo(bo)) { - placement->fpfn = 0; - placement->lpfn = 0; placement->placement = &placements; placement->busy_placement = &placements; placement->num_placement = 1; @@ -286,20 +289,20 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo, struct radeon_device *rdev; struct ttm_mem_reg *old_mem = &bo->mem; struct ttm_mem_reg tmp_mem; - u32 placements; + struct ttm_place placements; struct ttm_placement placement; int r; rdev = radeon_get_rdev(bo->bdev); tmp_mem = *new_mem; tmp_mem.mm_node = NULL; - placement.fpfn = 0; - placement.lpfn = 0; placement.num_placement = 1; placement.placement = &placements; placement.num_busy_placement = 1; placement.busy_placement = &placements; - placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; + placements.fpfn = 0; + placements.lpfn = 0; + placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; r = ttm_bo_mem_space(bo, &placement, &tmp_mem, interruptible, no_wait_gpu); if (unlikely(r)) { @@ -334,19 +337,19 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo, struct ttm_mem_reg *old_mem = &bo->mem; struct ttm_mem_reg tmp_mem; struct ttm_placement placement; - u32 placements; + struct ttm_place placements; int r; rdev = radeon_get_rdev(bo->bdev); tmp_mem = *new_mem; tmp_mem.mm_node = NULL; - placement.fpfn = 0; - placement.lpfn = 0; placement.num_placement = 1; placement.placement = &placements; placement.num_busy_placement = 1; placement.busy_placement = &placements; - placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; + placements.fpfn = 0; + placements.lpfn = 0; + placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT; r = ttm_bo_mem_space(bo, &placement, &tmp_mem, interruptible, no_wait_gpu); if (unlikely(r)) { diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 341848a14376..25c8a1fd152c 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -233,8 +233,12 @@ int radeon_uvd_resume(struct radeon_device *rdev) void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo) { - rbo->placement.fpfn = 0 >> PAGE_SHIFT; - rbo->placement.lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; + int i; + + for (i = 0; i < rbo->placement.num_placement; ++i) { + rbo->placements[i].fpfn = 0 >> PAGE_SHIFT; + rbo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; + } } void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 3da89d5dab60..b992ec3c318a 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -53,12 +53,13 @@ static struct attribute ttm_bo_count = { .mode = S_IRUGO }; -static inline int ttm_mem_type_from_flags(uint32_t flags, uint32_t *mem_type) +static inline int ttm_mem_type_from_place(const struct ttm_place *place, + uint32_t *mem_type) { int i; for (i = 0; i <= TTM_PL_PRIV5; i++) - if (flags & (1 << i)) { + if (place->flags & (1 << i)) { *mem_type = i; return 0; } @@ -89,12 +90,12 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo, bo, bo->mem.num_pages, bo->mem.size >> 10, bo->mem.size >> 20); for (i = 0; i < placement->num_placement; i++) { - ret = ttm_mem_type_from_flags(placement->placement[i], + ret = ttm_mem_type_from_place(&placement->placement[i], &mem_type); if (ret) return; pr_err(" placement[%d]=0x%08X (%d)\n", - i, placement->placement[i], mem_type); + i, placement->placement[i].flags, mem_type); ttm_mem_type_debug(bo->bdev, mem_type); } } @@ -685,8 +686,6 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, evict_mem.bus.io_reserved_vm = false; evict_mem.bus.io_reserved_count = 0; - placement.fpfn = 0; - placement.lpfn = 0; placement.num_placement = 0; placement.num_busy_placement = 0; bdev->driver->evict_flags(bo, &placement); @@ -774,7 +773,7 @@ EXPORT_SYMBOL(ttm_bo_mem_put); */ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, uint32_t mem_type, - struct ttm_placement *placement, + const struct ttm_place *place, struct ttm_mem_reg *mem, bool interruptible, bool no_wait_gpu) @@ -784,7 +783,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, int ret; do { - ret = (*man->func->get_node)(man, bo, placement, 0, mem); + ret = (*man->func->get_node)(man, bo, place, mem); if (unlikely(ret != 0)) return ret; if (mem->mm_node) @@ -827,18 +826,18 @@ static uint32_t ttm_bo_select_caching(struct ttm_mem_type_manager *man, static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man, uint32_t mem_type, - uint32_t proposed_placement, + const struct ttm_place *place, uint32_t *masked_placement) { uint32_t cur_flags = ttm_bo_type_flags(mem_type); - if ((cur_flags & proposed_placement & TTM_PL_MASK_MEM) == 0) + if ((cur_flags & place->flags & TTM_PL_MASK_MEM) == 0) return false; - if ((proposed_placement & man->available_caching) == 0) + if ((place->flags & man->available_caching) == 0) return false; - cur_flags |= (proposed_placement & man->available_caching); + cur_flags |= (place->flags & man->available_caching); *masked_placement = cur_flags; return true; @@ -869,15 +868,14 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, mem->mm_node = NULL; for (i = 0; i < placement->num_placement; ++i) { - ret = ttm_mem_type_from_flags(placement->placement[i], - &mem_type); + const struct ttm_place *place = &placement->placement[i]; + + ret = ttm_mem_type_from_place(place, &mem_type); if (ret) return ret; man = &bdev->man[mem_type]; - type_ok = ttm_bo_mt_compatible(man, - mem_type, - placement->placement[i], + type_ok = ttm_bo_mt_compatible(man, mem_type, place, &cur_flags); if (!type_ok) @@ -889,7 +887,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, * Use the access and other non-mapping-related flag bits from * the memory placement flags to the current flags */ - ttm_flag_masked(&cur_flags, placement->placement[i], + ttm_flag_masked(&cur_flags, place->flags, ~TTM_PL_MASK_MEMTYPE); if (mem_type == TTM_PL_SYSTEM) @@ -897,8 +895,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, if (man->has_type && man->use_type) { type_found = true; - ret = (*man->func->get_node)(man, bo, placement, - cur_flags, mem); + ret = (*man->func->get_node)(man, bo, place, mem); if (unlikely(ret)) return ret; } @@ -916,17 +913,15 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, return -EINVAL; for (i = 0; i < placement->num_busy_placement; ++i) { - ret = ttm_mem_type_from_flags(placement->busy_placement[i], - &mem_type); + const struct ttm_place *place = &placement->busy_placement[i]; + + ret = ttm_mem_type_from_place(place, &mem_type); if (ret) return ret; man = &bdev->man[mem_type]; if (!man->has_type) continue; - if (!ttm_bo_mt_compatible(man, - mem_type, - placement->busy_placement[i], - &cur_flags)) + if (!ttm_bo_mt_compatible(man, mem_type, place, &cur_flags)) continue; cur_flags = ttm_bo_select_caching(man, bo->mem.placement, @@ -935,7 +930,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, * Use the access and other non-mapping-related flag bits from * the memory placement flags to the current flags */ - ttm_flag_masked(&cur_flags, placement->busy_placement[i], + ttm_flag_masked(&cur_flags, place->flags, ~TTM_PL_MASK_MEMTYPE); if (mem_type == TTM_PL_SYSTEM) { @@ -945,7 +940,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, return 0; } - ret = ttm_bo_mem_force_space(bo, mem_type, placement, mem, + ret = ttm_bo_mem_force_space(bo, mem_type, place, mem, interruptible, no_wait_gpu); if (ret == 0 && mem->mm_node) { mem->placement = cur_flags; @@ -1006,20 +1001,27 @@ static bool ttm_bo_mem_compat(struct ttm_placement *placement, { int i; - if (mem->mm_node && placement->lpfn != 0 && - (mem->start < placement->fpfn || - mem->start + mem->num_pages > placement->lpfn)) - return false; - for (i = 0; i < placement->num_placement; i++) { - *new_flags = placement->placement[i]; + const struct ttm_place *heap = &placement->placement[i]; + if (mem->mm_node && heap->lpfn != 0 && + (mem->start < heap->fpfn || + mem->start + mem->num_pages > heap->lpfn)) + continue; + + *new_flags = heap->flags; if ((*new_flags & mem->placement & TTM_PL_MASK_CACHING) && (*new_flags & mem->placement & TTM_PL_MASK_MEM)) return true; } for (i = 0; i < placement->num_busy_placement; i++) { - *new_flags = placement->busy_placement[i]; + const struct ttm_place *heap = &placement->busy_placement[i]; + if (mem->mm_node && heap->lpfn != 0 && + (mem->start < heap->fpfn || + mem->start + mem->num_pages > heap->lpfn)) + continue; + + *new_flags = heap->flags; if ((*new_flags & mem->placement & TTM_PL_MASK_CACHING) && (*new_flags & mem->placement & TTM_PL_MASK_MEM)) return true; @@ -1037,11 +1039,6 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, uint32_t new_flags; lockdep_assert_held(&bo->resv->lock.base); - /* Check that range is valid */ - if (placement->lpfn || placement->fpfn) - if (placement->fpfn > placement->lpfn || - (placement->lpfn - placement->fpfn) < bo->num_pages) - return -EINVAL; /* * Check whether we need to move buffer. */ @@ -1070,15 +1067,6 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, } EXPORT_SYMBOL(ttm_bo_validate); -int ttm_bo_check_placement(struct ttm_buffer_object *bo, - struct ttm_placement *placement) -{ - BUG_ON((placement->fpfn || placement->lpfn) && - (bo->mem.num_pages > (placement->lpfn - placement->fpfn))); - - return 0; -} - int ttm_bo_init(struct ttm_bo_device *bdev, struct ttm_buffer_object *bo, unsigned long size, @@ -1147,15 +1135,12 @@ int ttm_bo_init(struct ttm_bo_device *bdev, atomic_inc(&bo->glob->bo_count); drm_vma_node_reset(&bo->vma_node); - ret = ttm_bo_check_placement(bo, placement); - /* * For ttm_bo_type_device buffers, allocate * address space from the device. */ - if (likely(!ret) && - (bo->type == ttm_bo_type_device || - bo->type == ttm_bo_type_sg)) + if (bo->type == ttm_bo_type_device || + bo->type == ttm_bo_type_sg) ret = drm_vma_offset_add(&bdev->vma_manager, &bo->vma_node, bo->mem.num_pages); diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c index 9e103a4875c8..964387fc5c8f 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_manager.c +++ b/drivers/gpu/drm/ttm/ttm_bo_manager.c @@ -49,8 +49,7 @@ struct ttm_range_manager { static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, struct ttm_buffer_object *bo, - struct ttm_placement *placement, - uint32_t flags, + const struct ttm_place *place, struct ttm_mem_reg *mem) { struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; @@ -60,7 +59,7 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, unsigned long lpfn; int ret; - lpfn = placement->lpfn; + lpfn = place->lpfn; if (!lpfn) lpfn = man->size; @@ -68,13 +67,13 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, if (!node) return -ENOMEM; - if (flags & TTM_PL_FLAG_TOPDOWN) + if (place->flags & TTM_PL_FLAG_TOPDOWN) aflags = DRM_MM_CREATE_TOP; spin_lock(&rman->lock); ret = drm_mm_insert_node_in_range_generic(mm, node, mem->num_pages, mem->page_alignment, 0, - placement->fpfn, lpfn, + place->fpfn, lpfn, DRM_MM_SEARCH_BEST, aflags); spin_unlock(&rman->lock); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 6327cfc36805..37c093c0c7b8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -30,66 +30,101 @@ #include #include -static uint32_t vram_placement_flags = TTM_PL_FLAG_VRAM | - TTM_PL_FLAG_CACHED; - -static uint32_t vram_ne_placement_flags = TTM_PL_FLAG_VRAM | - TTM_PL_FLAG_CACHED | - TTM_PL_FLAG_NO_EVICT; +static struct ttm_place vram_placement_flags = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED +}; -static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM | - TTM_PL_FLAG_CACHED; +static struct ttm_place vram_ne_placement_flags = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT +}; -static uint32_t sys_ne_placement_flags = TTM_PL_FLAG_SYSTEM | - TTM_PL_FLAG_CACHED | - TTM_PL_FLAG_NO_EVICT; +static struct ttm_place sys_placement_flags = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED +}; -static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR | - TTM_PL_FLAG_CACHED; +static struct ttm_place sys_ne_placement_flags = { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT +}; -static uint32_t gmr_ne_placement_flags = VMW_PL_FLAG_GMR | - TTM_PL_FLAG_CACHED | - TTM_PL_FLAG_NO_EVICT; +static struct ttm_place gmr_placement_flags = { + .fpfn = 0, + .lpfn = 0, + .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED +}; -static uint32_t mob_placement_flags = VMW_PL_FLAG_MOB | - TTM_PL_FLAG_CACHED; +static struct ttm_place gmr_ne_placement_flags = { + .fpfn = 0, + .lpfn = 0, + .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT +}; -struct ttm_placement vmw_vram_placement = { +static struct ttm_place mob_placement_flags = { .fpfn = 0, .lpfn = 0, + .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED +}; + +struct ttm_placement vmw_vram_placement = { .num_placement = 1, .placement = &vram_placement_flags, .num_busy_placement = 1, .busy_placement = &vram_placement_flags }; -static uint32_t vram_gmr_placement_flags[] = { - TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED, - VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED +static struct ttm_place vram_gmr_placement_flags[] = { + { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED + }, { + .fpfn = 0, + .lpfn = 0, + .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED + } }; -static uint32_t gmr_vram_placement_flags[] = { - VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED, - TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED +static struct ttm_place gmr_vram_placement_flags[] = { + { + .fpfn = 0, + .lpfn = 0, + .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED + }, { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED + } }; struct ttm_placement vmw_vram_gmr_placement = { - .fpfn = 0, - .lpfn = 0, .num_placement = 2, .placement = vram_gmr_placement_flags, .num_busy_placement = 1, .busy_placement = &gmr_placement_flags }; -static uint32_t vram_gmr_ne_placement_flags[] = { - TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT, - VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT +static struct ttm_place vram_gmr_ne_placement_flags[] = { + { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED | + TTM_PL_FLAG_NO_EVICT + }, { + .fpfn = 0, + .lpfn = 0, + .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED | + TTM_PL_FLAG_NO_EVICT + } }; struct ttm_placement vmw_vram_gmr_ne_placement = { - .fpfn = 0, - .lpfn = 0, .num_placement = 2, .placement = vram_gmr_ne_placement_flags, .num_busy_placement = 1, @@ -97,8 +132,6 @@ struct ttm_placement vmw_vram_gmr_ne_placement = { }; struct ttm_placement vmw_vram_sys_placement = { - .fpfn = 0, - .lpfn = 0, .num_placement = 1, .placement = &vram_placement_flags, .num_busy_placement = 1, @@ -106,8 +139,6 @@ struct ttm_placement vmw_vram_sys_placement = { }; struct ttm_placement vmw_vram_ne_placement = { - .fpfn = 0, - .lpfn = 0, .num_placement = 1, .placement = &vram_ne_placement_flags, .num_busy_placement = 1, @@ -115,8 +146,6 @@ struct ttm_placement vmw_vram_ne_placement = { }; struct ttm_placement vmw_sys_placement = { - .fpfn = 0, - .lpfn = 0, .num_placement = 1, .placement = &sys_placement_flags, .num_busy_placement = 1, @@ -124,24 +153,33 @@ struct ttm_placement vmw_sys_placement = { }; struct ttm_placement vmw_sys_ne_placement = { - .fpfn = 0, - .lpfn = 0, .num_placement = 1, .placement = &sys_ne_placement_flags, .num_busy_placement = 1, .busy_placement = &sys_ne_placement_flags }; -static uint32_t evictable_placement_flags[] = { - TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED, - TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED, - VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED, - VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED +static struct ttm_place evictable_placement_flags[] = { + { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED + }, { + .fpfn = 0, + .lpfn = 0, + .flags = TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED + }, { + .fpfn = 0, + .lpfn = 0, + .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED + }, { + .fpfn = 0, + .lpfn = 0, + .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED + } }; struct ttm_placement vmw_evictable_placement = { - .fpfn = 0, - .lpfn = 0, .num_placement = 4, .placement = evictable_placement_flags, .num_busy_placement = 1, @@ -149,8 +187,6 @@ struct ttm_placement vmw_evictable_placement = { }; struct ttm_placement vmw_srf_placement = { - .fpfn = 0, - .lpfn = 0, .num_placement = 1, .num_busy_placement = 2, .placement = &gmr_placement_flags, @@ -158,8 +194,6 @@ struct ttm_placement vmw_srf_placement = { }; struct ttm_placement vmw_mob_placement = { - .fpfn = 0, - .lpfn = 0, .num_placement = 1, .num_busy_placement = 1, .placement = &mob_placement_flags, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index ed1d51006ab1..914b375763dc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c @@ -198,13 +198,19 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv, { struct ttm_buffer_object *bo = &buf->base; struct ttm_placement placement; + struct ttm_place place; int ret = 0; if (pin) - placement = vmw_vram_ne_placement; + place = vmw_vram_ne_placement.placement[0]; else - placement = vmw_vram_placement; - placement.lpfn = bo->num_pages; + place = vmw_vram_placement.placement[0]; + place.lpfn = bo->num_pages; + + placement.num_placement = 1; + placement.placement = &place; + placement.num_busy_placement = 1; + placement.busy_placement = &place; ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) @@ -293,21 +299,23 @@ void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *bo, */ void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin) { - uint32_t pl_flags; + struct ttm_place pl; struct ttm_placement placement; uint32_t old_mem_type = bo->mem.mem_type; int ret; lockdep_assert_held(&bo->resv->lock.base); - pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB + pl.fpfn = 0; + pl.lpfn = 0; + pl.flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB | TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED; if (pin) - pl_flags |= TTM_PL_FLAG_NO_EVICT; + pl.flags |= TTM_PL_FLAG_NO_EVICT; memset(&placement, 0, sizeof(placement)); placement.num_placement = 1; - placement.placement = &pl_flags; + placement.placement = &pl; ret = ttm_bo_validate(bo, &placement, false, true); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index b031b48dbb3c..0a474f391fad 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -374,10 +374,16 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, size_t size, struct vmw_dma_buffer **out) { struct vmw_dma_buffer *vmw_bo; - struct ttm_placement ne_placement = vmw_vram_ne_placement; + struct ttm_place ne_place = vmw_vram_ne_placement.placement[0]; + struct ttm_placement ne_placement; int ret; - ne_placement.lpfn = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + ne_placement.num_placement = 1; + ne_placement.placement = &ne_place; + ne_placement.num_busy_placement = 1; + ne_placement.busy_placement = &ne_place; + + ne_place.lpfn = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; (void) ttm_write_lock(&vmw_priv->reservation_sem, false); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index 26f8bdde3529..170b61be1e4e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -46,8 +46,7 @@ struct vmwgfx_gmrid_man { static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man, struct ttm_buffer_object *bo, - struct ttm_placement *placement, - uint32_t flags, + const struct ttm_place *place, struct ttm_mem_reg *mem) { struct vmwgfx_gmrid_man *gman = diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 7526c5bf5610..e3d39c80a091 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -45,12 +45,24 @@ struct ttm_bo_device; struct drm_mm_node; +/** + * struct ttm_place + * + * @fpfn: first valid page frame number to put the object + * @lpfn: last valid page frame number to put the object + * @flags: memory domain and caching flags for the object + * + * Structure indicating a possible place to put an object. + */ +struct ttm_place { + unsigned fpfn; + unsigned lpfn; + uint32_t flags; +}; /** * struct ttm_placement * - * @fpfn: first valid page frame number to put the object - * @lpfn: last valid page frame number to put the object * @num_placement: number of preferred placements * @placement: preferred placements * @num_busy_placement: number of preferred placements when need to evict buffer @@ -59,12 +71,10 @@ struct drm_mm_node; * Structure indicating the placement you request for an object. */ struct ttm_placement { - unsigned fpfn; - unsigned lpfn; - unsigned num_placement; - const uint32_t *placement; - unsigned num_busy_placement; - const uint32_t *busy_placement; + unsigned num_placement; + const struct ttm_place *placement; + unsigned num_busy_placement; + const struct ttm_place *busy_placement; }; /** @@ -518,20 +528,6 @@ extern int ttm_bo_create(struct ttm_bo_device *bdev, struct file *persistent_swap_storage, struct ttm_buffer_object **p_bo); -/** - * ttm_bo_check_placement - * - * @bo: the buffer object. - * @placement: placements - * - * Performs minimal validity checking on an intended change of - * placement flags. - * Returns - * -EINVAL: Intended change is invalid or not allowed. - */ -extern int ttm_bo_check_placement(struct ttm_buffer_object *bo, - struct ttm_placement *placement); - /** * ttm_bo_init_mm * diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 1d9f0f1ff52d..5c8bb5699a6f 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -208,8 +208,7 @@ struct ttm_mem_type_manager_func { */ int (*get_node)(struct ttm_mem_type_manager *man, struct ttm_buffer_object *bo, - struct ttm_placement *placement, - uint32_t flags, + const struct ttm_place *place, struct ttm_mem_reg *mem); /** -- GitLab From 23f66e2d661b4d3226d16e25910a9e9472ce2410 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 27 Aug 2014 11:18:29 -0400 Subject: [PATCH 0714/5088] Revert "powerpc: Replace __get_cpu_var uses" This reverts commit 5828f666c069af74e00db21559f1535103c9f79a due to build failure after merging with pending powerpc changes. Link: http://lkml.kernel.org/g/20140827142243.6277eaff@canb.auug.org.au Signed-off-by: Tejun Heo Reported-by: Stephen Rothwell Cc: Christoph Lameter Cc: Benjamin Herrenschmidt --- arch/powerpc/include/asm/hardirq.h | 4 +--- arch/powerpc/include/asm/tlbflush.h | 4 ++-- arch/powerpc/include/asm/xics.h | 8 +++---- arch/powerpc/kernel/dbell.c | 2 +- arch/powerpc/kernel/hw_breakpoint.c | 6 ++--- arch/powerpc/kernel/iommu.c | 2 +- arch/powerpc/kernel/irq.c | 4 ++-- arch/powerpc/kernel/kgdb.c | 2 +- arch/powerpc/kernel/kprobes.c | 6 ++--- arch/powerpc/kernel/mce.c | 24 +++++++++---------- arch/powerpc/kernel/process.c | 10 ++++---- arch/powerpc/kernel/smp.c | 6 ++--- arch/powerpc/kernel/sysfs.c | 4 ++-- arch/powerpc/kernel/time.c | 22 ++++++++--------- arch/powerpc/kernel/traps.c | 8 +++---- arch/powerpc/kvm/e500.c | 14 +++++------ arch/powerpc/kvm/e500mc.c | 4 ++-- arch/powerpc/mm/hash_native_64.c | 2 +- arch/powerpc/mm/hash_utils_64.c | 2 +- arch/powerpc/mm/hugetlbpage-book3e.c | 6 ++--- arch/powerpc/mm/hugetlbpage.c | 2 +- arch/powerpc/perf/core-book3s.c | 22 ++++++++--------- arch/powerpc/perf/core-fsl-emb.c | 6 ++--- arch/powerpc/platforms/cell/interrupt.c | 6 ++--- .../platforms/powernv/opal-tracepoints.c | 4 ++-- arch/powerpc/platforms/ps3/interrupt.c | 2 +- arch/powerpc/platforms/pseries/dtl.c | 2 +- arch/powerpc/platforms/pseries/hvCall_inst.c | 4 ++-- arch/powerpc/platforms/pseries/iommu.c | 8 +++---- arch/powerpc/platforms/pseries/lpar.c | 6 ++--- arch/powerpc/platforms/pseries/ras.c | 4 ++-- arch/powerpc/sysdev/xics/xics-common.c | 2 +- 32 files changed, 103 insertions(+), 105 deletions(-) diff --git a/arch/powerpc/include/asm/hardirq.h b/arch/powerpc/include/asm/hardirq.h index 8d907ba4fd05..1bbb3013d6aa 100644 --- a/arch/powerpc/include/asm/hardirq.h +++ b/arch/powerpc/include/asm/hardirq.h @@ -21,9 +21,7 @@ DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); #define __ARCH_IRQ_STAT -#define local_softirq_pending() __this_cpu_read(irq_stat.__softirq_pending) -#define set_softirq_pending(x) __this_cpu_write(irq_stat._softirq_pending, (x)) -#define or_softirq_pending(x) __this_cpu_or(irq_stat._softirq_pending, (x)) +#define local_softirq_pending() __get_cpu_var(irq_stat).__softirq_pending static inline void ack_bad_irq(unsigned int irq) { diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index cd7c2719d3ef..2def01ed0cb2 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -107,14 +107,14 @@ extern void __flush_tlb_pending(struct ppc64_tlb_batch *batch); static inline void arch_enter_lazy_mmu_mode(void) { - struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); + struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); batch->active = 1; } static inline void arch_leave_lazy_mmu_mode(void) { - struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); + struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); if (batch->index) __flush_tlb_pending(batch); diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index 5007ad0448ce..282d43a0c855 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h @@ -97,7 +97,7 @@ DECLARE_PER_CPU(struct xics_cppr, xics_cppr); static inline void xics_push_cppr(unsigned int vec) { - struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1)) return; @@ -110,7 +110,7 @@ static inline void xics_push_cppr(unsigned int vec) static inline unsigned char xics_pop_cppr(void) { - struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); if (WARN_ON(os_cppr->index < 1)) return LOWEST_PRIORITY; @@ -120,7 +120,7 @@ static inline unsigned char xics_pop_cppr(void) static inline void xics_set_base_cppr(unsigned char cppr) { - struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); /* we only really want to set the priority when there's * just one cppr value on the stack @@ -132,7 +132,7 @@ static inline void xics_set_base_cppr(unsigned char cppr) static inline unsigned char xics_cppr_top(void) { - struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); return os_cppr->stack[os_cppr->index]; } diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index f4217819cc31..d55c76c571f3 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -41,7 +41,7 @@ void doorbell_exception(struct pt_regs *regs) may_hard_irq_enable(); - __this_cpu_inc(irq_stat.doorbell_irqs); + __get_cpu_var(irq_stat).doorbell_irqs++; smp_ipi_demux(); diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index b62f90eaf19e..0bb5918faaaf 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -63,7 +63,7 @@ int hw_breakpoint_slots(int type) int arch_install_hw_breakpoint(struct perf_event *bp) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); - struct perf_event **slot = this_cpu_ptr(&bp_per_reg); + struct perf_event **slot = &__get_cpu_var(bp_per_reg); *slot = bp; @@ -88,7 +88,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp) */ void arch_uninstall_hw_breakpoint(struct perf_event *bp) { - struct perf_event **slot = this_cpu_ptr(&bp_per_reg); + struct perf_event **slot = &__get_cpu_var(bp_per_reg); if (*slot != bp) { WARN_ONCE(1, "Can't find the breakpoint"); @@ -226,7 +226,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) */ rcu_read_lock(); - bp = __this_cpu_read(bp_per_reg); + bp = __get_cpu_var(bp_per_reg); if (!bp) goto out; info = counter_arch_bp(bp); diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 71e60bfb89e2..a10642a0d861 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -208,7 +208,7 @@ static unsigned long iommu_range_alloc(struct device *dev, * We don't need to disable preemption here because any CPU can * safely use any IOMMU pool. */ - pool_nr = __this_cpu_read(iommu_pool_hash) & (tbl->nr_pools - 1); + pool_nr = __raw_get_cpu_var(iommu_pool_hash) & (tbl->nr_pools - 1); if (largealloc) pool = &(tbl->large_pool); diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 74d40c6855b8..4c5891de162e 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -114,7 +114,7 @@ static inline notrace void set_soft_enabled(unsigned long enable) static inline notrace int decrementer_check_overflow(void) { u64 now = get_tb_or_rtc(); - u64 *next_tb = this_cpu_ptr(&decrementers_next_tb); + u64 *next_tb = &__get_cpu_var(decrementers_next_tb); return now >= *next_tb; } @@ -499,7 +499,7 @@ void __do_irq(struct pt_regs *regs) /* And finally process it */ if (unlikely(irq == NO_IRQ)) - __this_cpu_inc(irq_stat.spurious_irqs); + __get_cpu_var(irq_stat).spurious_irqs++; else generic_handle_irq(irq); diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index e77c3ccf8dcf..8504657379f1 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -155,7 +155,7 @@ static int kgdb_singlestep(struct pt_regs *regs) { struct thread_info *thread_info, *exception_thread_info; struct thread_info *backup_current_thread_info = - this_cpu_ptr(&kgdb_thread_info); + &__get_cpu_var(kgdb_thread_info); if (user_mode(regs)) return 0; diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 7c053f281406..2f72af82513c 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -119,7 +119,7 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) { - __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); + __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; kcb->kprobe_status = kcb->prev_kprobe.status; kcb->kprobe_saved_msr = kcb->prev_kprobe.saved_msr; } @@ -127,7 +127,7 @@ static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { - __this_cpu_write(current_kprobe, p); + __get_cpu_var(current_kprobe) = p; kcb->kprobe_saved_msr = regs->msr; } @@ -192,7 +192,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) ret = 1; goto no_kprobe; } - p = __this_cpu_read(current_kprobe); + p = __get_cpu_var(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) { goto ss_probe; } diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c index 15c99b649b04..a7fd4cb78b78 100644 --- a/arch/powerpc/kernel/mce.c +++ b/arch/powerpc/kernel/mce.c @@ -73,8 +73,8 @@ void save_mce_event(struct pt_regs *regs, long handled, uint64_t nip, uint64_t addr) { uint64_t srr1; - int index = __this_cpu_inc_return(mce_nest_count); - struct machine_check_event *mce = this_cpu_ptr(&mce_event[index]); + int index = __get_cpu_var(mce_nest_count)++; + struct machine_check_event *mce = &__get_cpu_var(mce_event[index]); /* * Return if we don't have enough space to log mce event. @@ -143,7 +143,7 @@ void save_mce_event(struct pt_regs *regs, long handled, */ int get_mce_event(struct machine_check_event *mce, bool release) { - int index = __this_cpu_read(mce_nest_count) - 1; + int index = __get_cpu_var(mce_nest_count) - 1; struct machine_check_event *mc_evt; int ret = 0; @@ -153,7 +153,7 @@ int get_mce_event(struct machine_check_event *mce, bool release) /* Check if we have MCE info to process. */ if (index < MAX_MC_EVT) { - mc_evt = this_cpu_ptr(&mce_event[index]); + mc_evt = &__get_cpu_var(mce_event[index]); /* Copy the event structure and release the original */ if (mce) *mce = *mc_evt; @@ -163,7 +163,7 @@ int get_mce_event(struct machine_check_event *mce, bool release) } /* Decrement the count to free the slot. */ if (release) - __this_cpu_dec(mce_nest_count); + __get_cpu_var(mce_nest_count)--; return ret; } @@ -184,13 +184,13 @@ void machine_check_queue_event(void) if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) return; - index = __this_cpu_inc_return(mce_queue_count); + index = __get_cpu_var(mce_queue_count)++; /* If queue is full, just return for now. */ if (index >= MAX_MC_EVT) { - __this_cpu_dec(mce_queue_count); + __get_cpu_var(mce_queue_count)--; return; } - memcpy(this_cpu_ptr(&mce_event_queue[index]), &evt, sizeof(evt)); + __get_cpu_var(mce_event_queue[index]) = evt; /* Queue irq work to process this event later. */ irq_work_queue(&mce_event_process_work); @@ -208,11 +208,11 @@ static void machine_check_process_queued_event(struct irq_work *work) * For now just print it to console. * TODO: log this error event to FSP or nvram. */ - while (__this_cpu_read(mce_queue_count) > 0) { - index = __this_cpu_read(mce_queue_count) - 1; + while (__get_cpu_var(mce_queue_count) > 0) { + index = __get_cpu_var(mce_queue_count) - 1; machine_check_print_event_info( - this_cpu_ptr(&mce_event_queue[index])); - __this_cpu_dec(mce_queue_count); + &__get_cpu_var(mce_event_queue[index])); + __get_cpu_var(mce_queue_count)--; } } diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 2df2f2956520..bf44ae962ab8 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -498,7 +498,7 @@ static inline int set_dawr(struct arch_hw_breakpoint *brk) void __set_breakpoint(struct arch_hw_breakpoint *brk) { - __this_cpu_write(current_brk, *brk); + __get_cpu_var(current_brk) = *brk; if (cpu_has_feature(CPU_FTR_DAWR)) set_dawr(brk); @@ -841,7 +841,7 @@ struct task_struct *__switch_to(struct task_struct *prev, * schedule DABR */ #ifndef CONFIG_HAVE_HW_BREAKPOINT - if (unlikely(!hw_brk_match(this_cpu_ptr(¤t_brk), &new->thread.hw_brk))) + if (unlikely(!hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk))) __set_breakpoint(&new->thread.hw_brk); #endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif @@ -855,7 +855,7 @@ struct task_struct *__switch_to(struct task_struct *prev, * Collect processor utilization data per process */ if (firmware_has_feature(FW_FEATURE_SPLPAR)) { - struct cpu_usage *cu = this_cpu_ptr(&cpu_usage_array); + struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); long unsigned start_tb, current_tb; start_tb = old_thread->start_tb; cu->current_tb = current_tb = mfspr(SPRN_PURR); @@ -865,7 +865,7 @@ struct task_struct *__switch_to(struct task_struct *prev, #endif /* CONFIG_PPC64 */ #ifdef CONFIG_PPC_BOOK3S_64 - batch = this_cpu_ptr(&ppc64_tlb_batch); + batch = &__get_cpu_var(ppc64_tlb_batch); if (batch->active) { current_thread_info()->local_flags |= _TLF_LAZY_MMU; if (batch->index) @@ -888,7 +888,7 @@ struct task_struct *__switch_to(struct task_struct *prev, #ifdef CONFIG_PPC_BOOK3S_64 if (current_thread_info()->local_flags & _TLF_LAZY_MMU) { current_thread_info()->local_flags &= ~_TLF_LAZY_MMU; - batch = this_cpu_ptr(&ppc64_tlb_batch); + batch = &__get_cpu_var(ppc64_tlb_batch); batch->active = 1; } #endif /* CONFIG_PPC_BOOK3S_64 */ diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 60391a51467a..a0738af4aba6 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -242,7 +242,7 @@ void smp_muxed_ipi_message_pass(int cpu, int msg) irqreturn_t smp_ipi_demux(void) { - struct cpu_messages *info = this_cpu_ptr(&ipi_message); + struct cpu_messages *info = &__get_cpu_var(ipi_message); unsigned int all; mb(); /* order any irq clear */ @@ -438,9 +438,9 @@ void generic_mach_cpu_die(void) idle_task_exit(); cpu = smp_processor_id(); printk(KERN_DEBUG "CPU%d offline\n", cpu); - __this_cpu_write(cpu_state, CPU_DEAD); + __get_cpu_var(cpu_state) = CPU_DEAD; smp_wmb(); - while (__this_cpu_read(cpu_state) != CPU_UP_PREPARE) + while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) cpu_relax(); } diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index fa1fd8a0c867..67fd2fd2620a 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -394,10 +394,10 @@ void ppc_enable_pmcs(void) ppc_set_pmu_inuse(1); /* Only need to enable them once */ - if (__this_cpu_read(pmcs_enabled)) + if (__get_cpu_var(pmcs_enabled)) return; - __this_cpu_write(pmcs_enabled, 1); + __get_cpu_var(pmcs_enabled) = 1; if (ppc_md.enable_pmcs) ppc_md.enable_pmcs(); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 4769e5b7f905..368ab374d33c 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -458,9 +458,9 @@ static inline void clear_irq_work_pending(void) DEFINE_PER_CPU(u8, irq_work_pending); -#define set_irq_work_pending_flag() __this_cpu_write(irq_work_pending, 1) -#define test_irq_work_pending() __this_cpu_read(irq_work_pending) -#define clear_irq_work_pending() __this_cpu_write(irq_work_pending, 0) +#define set_irq_work_pending_flag() __get_cpu_var(irq_work_pending) = 1 +#define test_irq_work_pending() __get_cpu_var(irq_work_pending) +#define clear_irq_work_pending() __get_cpu_var(irq_work_pending) = 0 #endif /* 32 vs 64 bit */ @@ -482,8 +482,8 @@ void arch_irq_work_raise(void) void __timer_interrupt(void) { struct pt_regs *regs = get_irq_regs(); - u64 *next_tb = this_cpu_ptr(&decrementers_next_tb); - struct clock_event_device *evt = this_cpu_ptr(&decrementers); + u64 *next_tb = &__get_cpu_var(decrementers_next_tb); + struct clock_event_device *evt = &__get_cpu_var(decrementers); u64 now; trace_timer_interrupt_entry(regs); @@ -498,7 +498,7 @@ void __timer_interrupt(void) *next_tb = ~(u64)0; if (evt->event_handler) evt->event_handler(evt); - __this_cpu_inc(irq_stat.timer_irqs_event); + __get_cpu_var(irq_stat).timer_irqs_event++; } else { now = *next_tb - now; if (now <= DECREMENTER_MAX) @@ -506,13 +506,13 @@ void __timer_interrupt(void) /* We may have raced with new irq work */ if (test_irq_work_pending()) set_dec(1); - __this_cpu_inc(irq_stat.timer_irqs_others); + __get_cpu_var(irq_stat).timer_irqs_others++; } #ifdef CONFIG_PPC64 /* collect purr register values often, for accurate calculations */ if (firmware_has_feature(FW_FEATURE_SPLPAR)) { - struct cpu_usage *cu = this_cpu_ptr(&cpu_usage_array); + struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); cu->current_tb = mfspr(SPRN_PURR); } #endif @@ -527,7 +527,7 @@ void __timer_interrupt(void) void timer_interrupt(struct pt_regs * regs) { struct pt_regs *old_regs; - u64 *next_tb = this_cpu_ptr(&decrementers_next_tb); + u64 *next_tb = &__get_cpu_var(decrementers_next_tb); /* Ensure a positive value is written to the decrementer, or else * some CPUs will continue to take decrementer exceptions. @@ -813,7 +813,7 @@ static void __init clocksource_init(void) static int decrementer_set_next_event(unsigned long evt, struct clock_event_device *dev) { - __this_cpu_write(decrementers_next_tb, get_tb_or_rtc() + evt); + __get_cpu_var(decrementers_next_tb) = get_tb_or_rtc() + evt; set_dec(evt); /* We may have raced with new irq work */ @@ -833,7 +833,7 @@ static void decrementer_set_mode(enum clock_event_mode mode, /* Interrupt handler for the timer broadcast IPI */ void tick_broadcast_ipi_handler(void) { - u64 *next_tb = this_cpu_ptr(&decrementers_next_tb); + u64 *next_tb = &__get_cpu_var(decrementers_next_tb); *next_tb = get_tb_or_rtc(); __timer_interrupt(); diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index e6595b72269b..0dc43f9932cf 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -295,7 +295,7 @@ long machine_check_early(struct pt_regs *regs) { long handled = 0; - __this_cpu_inc(irq_stat.mce_exceptions); + __get_cpu_var(irq_stat).mce_exceptions++; if (cur_cpu_spec && cur_cpu_spec->machine_check_early) handled = cur_cpu_spec->machine_check_early(regs); @@ -304,7 +304,7 @@ long machine_check_early(struct pt_regs *regs) long hmi_exception_realmode(struct pt_regs *regs) { - __this_cpu_inc(irq_stat.hmi_exceptions); + __get_cpu_var(irq_stat).hmi_exceptions++; if (ppc_md.hmi_exception_early) ppc_md.hmi_exception_early(regs); @@ -700,7 +700,7 @@ void machine_check_exception(struct pt_regs *regs) enum ctx_state prev_state = exception_enter(); int recover = 0; - __this_cpu_inc(irq_stat.mce_exceptions); + __get_cpu_var(irq_stat).mce_exceptions++; /* See if any machine dependent calls. In theory, we would want * to call the CPU first, and call the ppc_md. one if the CPU @@ -1519,7 +1519,7 @@ void vsx_unavailable_tm(struct pt_regs *regs) void performance_monitor_exception(struct pt_regs *regs) { - __this_cpu_inc(irq_stat.pmu_irqs); + __get_cpu_var(irq_stat).pmu_irqs++; perf_irq(regs); } diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c index 16095841afe1..2e02ed849f36 100644 --- a/arch/powerpc/kvm/e500.c +++ b/arch/powerpc/kvm/e500.c @@ -76,11 +76,11 @@ static inline int local_sid_setup_one(struct id *entry) unsigned long sid; int ret = -1; - sid = __this_cpu_inc_return(pcpu_last_used_sid); + sid = ++(__get_cpu_var(pcpu_last_used_sid)); if (sid < NUM_TIDS) { - __this_cpu_write(pcpu_sids)entry[sid], entry); + __get_cpu_var(pcpu_sids).entry[sid] = entry; entry->val = sid; - entry->pentry = this_cpu_ptr(&pcpu_sids.entry[sid]); + entry->pentry = &__get_cpu_var(pcpu_sids).entry[sid]; ret = sid; } @@ -108,8 +108,8 @@ static inline int local_sid_setup_one(struct id *entry) static inline int local_sid_lookup(struct id *entry) { if (entry && entry->val != 0 && - __this_cpu_read(pcpu_sids.entry[entry->val]) == entry && - entry->pentry == this_cpu_ptr(&pcpu_sids.entry[entry->val])) + __get_cpu_var(pcpu_sids).entry[entry->val] == entry && + entry->pentry == &__get_cpu_var(pcpu_sids).entry[entry->val]) return entry->val; return -1; } @@ -117,8 +117,8 @@ static inline int local_sid_lookup(struct id *entry) /* Invalidate all id mappings on local core -- call with preempt disabled */ static inline void local_sid_destroy_all(void) { - __this_cpu_write(pcpu_last_used_sid, 0); - memset(this_cpu_ptr(&pcpu_sids), 0, sizeof(pcpu_sids)); + __get_cpu_var(pcpu_last_used_sid) = 0; + memset(&__get_cpu_var(pcpu_sids), 0, sizeof(__get_cpu_var(pcpu_sids))); } static void *kvmppc_e500_id_table_alloc(struct kvmppc_vcpu_e500 *vcpu_e500) diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c index 6ef54e523f33..164bad2a19bf 100644 --- a/arch/powerpc/kvm/e500mc.c +++ b/arch/powerpc/kvm/e500mc.c @@ -141,9 +141,9 @@ static void kvmppc_core_vcpu_load_e500mc(struct kvm_vcpu *vcpu, int cpu) mtspr(SPRN_GESR, vcpu->arch.shared->esr); if (vcpu->arch.oldpir != mfspr(SPRN_PIR) || - __this_cpu_read(last_vcpu_of_lpid[vcpu->kvm->arch.lpid]) != vcpu) { + __get_cpu_var(last_vcpu_of_lpid)[vcpu->kvm->arch.lpid] != vcpu) { kvmppc_e500_tlbil_all(vcpu_e500); - __this_cpu_write(last_vcpu_of_lpid[vcpu->kvm->arch.lpid], vcpu); + __get_cpu_var(last_vcpu_of_lpid)[vcpu->kvm->arch.lpid] = vcpu; } kvmppc_load_guest_fp(vcpu); diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 504a16f1a1a0..afc0a8295f84 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -625,7 +625,7 @@ static void native_flush_hash_range(unsigned long number, int local) unsigned long want_v; unsigned long flags; real_pte_t pte; - struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); + struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); unsigned long psize = batch->psize; int ssize = batch->ssize; int i; diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 060d51fda35e..daee7f4e5a14 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1314,7 +1314,7 @@ void flush_hash_range(unsigned long number, int local) else { int i; struct ppc64_tlb_batch *batch = - this_cpu_ptr(&ppc64_tlb_batch); + &__get_cpu_var(ppc64_tlb_batch); for (i = 0; i < number; i++) flush_hash_page(batch->vpn[i], batch->pte[i], diff --git a/arch/powerpc/mm/hugetlbpage-book3e.c b/arch/powerpc/mm/hugetlbpage-book3e.c index ba47aaf33a4b..5e4ee2573903 100644 --- a/arch/powerpc/mm/hugetlbpage-book3e.c +++ b/arch/powerpc/mm/hugetlbpage-book3e.c @@ -33,13 +33,13 @@ static inline int tlb1_next(void) ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY; - index = this_cpu_read(next_tlbcam_idx); + index = __get_cpu_var(next_tlbcam_idx); /* Just round-robin the entries and wrap when we hit the end */ if (unlikely(index == ncams - 1)) - __this_cpu_write(next_tlbcam_idx, tlbcam_index); + __get_cpu_var(next_tlbcam_idx) = tlbcam_index; else - __this_cpu_inc(next_tlbcam_idx); + __get_cpu_var(next_tlbcam_idx)++; return index; } diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 8aa04f03fd31..7e70ae968e5f 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -462,7 +462,7 @@ static void hugepd_free(struct mmu_gather *tlb, void *hugepte) { struct hugepd_freelist **batchp; - batchp = this_cpu_ptr(&hugepd_freelist_cur); + batchp = &get_cpu_var(hugepd_freelist_cur); if (atomic_read(&tlb->mm->mm_users) < 2 || cpumask_equal(mm_cpumask(tlb->mm), diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 690f9c7bf3c8..b7cd00b0171e 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -339,7 +339,7 @@ static void power_pmu_bhrb_reset(void) static void power_pmu_bhrb_enable(struct perf_event *event) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); if (!ppmu->bhrb_nr) return; @@ -354,7 +354,7 @@ static void power_pmu_bhrb_enable(struct perf_event *event) static void power_pmu_bhrb_disable(struct perf_event *event) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); if (!ppmu->bhrb_nr) return; @@ -1144,7 +1144,7 @@ static void power_pmu_disable(struct pmu *pmu) if (!ppmu) return; local_irq_save(flags); - cpuhw = this_cpu_ptr(&cpu_hw_events); + cpuhw = &__get_cpu_var(cpu_hw_events); if (!cpuhw->disabled) { /* @@ -1211,7 +1211,7 @@ static void power_pmu_enable(struct pmu *pmu) return; local_irq_save(flags); - cpuhw = this_cpu_ptr(&cpu_hw_events); + cpuhw = &__get_cpu_var(cpu_hw_events); if (!cpuhw->disabled) goto out; @@ -1403,7 +1403,7 @@ static int power_pmu_add(struct perf_event *event, int ef_flags) * Add the event to the list (if there is room) * and check whether the total set is still feasible. */ - cpuhw = this_cpu_ptr(&cpu_hw_events); + cpuhw = &__get_cpu_var(cpu_hw_events); n0 = cpuhw->n_events; if (n0 >= ppmu->n_counter) goto out; @@ -1469,7 +1469,7 @@ static void power_pmu_del(struct perf_event *event, int ef_flags) power_pmu_read(event); - cpuhw = this_cpu_ptr(&cpu_hw_events); + cpuhw = &__get_cpu_var(cpu_hw_events); for (i = 0; i < cpuhw->n_events; ++i) { if (event == cpuhw->event[i]) { while (++i < cpuhw->n_events) { @@ -1575,7 +1575,7 @@ static void power_pmu_stop(struct perf_event *event, int ef_flags) */ void power_pmu_start_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); perf_pmu_disable(pmu); cpuhw->group_flag |= PERF_EVENT_TXN; @@ -1589,7 +1589,7 @@ void power_pmu_start_txn(struct pmu *pmu) */ void power_pmu_cancel_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); cpuhw->group_flag &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); @@ -1607,7 +1607,7 @@ int power_pmu_commit_txn(struct pmu *pmu) if (!ppmu) return -EAGAIN; - cpuhw = this_cpu_ptr(&cpu_hw_events); + cpuhw = &__get_cpu_var(cpu_hw_events); n = cpuhw->n_events; if (check_excludes(cpuhw->event, cpuhw->flags, 0, n)) return -EAGAIN; @@ -1964,7 +1964,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, if (event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK) { struct cpu_hw_events *cpuhw; - cpuhw = this_cpu_ptr(&cpu_hw_events); + cpuhw = &__get_cpu_var(cpu_hw_events); power_pmu_bhrb_read(cpuhw); data.br_stack = &cpuhw->bhrb_stack; } @@ -2037,7 +2037,7 @@ static bool pmc_overflow(unsigned long val) static void perf_event_interrupt(struct pt_regs *regs) { int i, j; - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); struct perf_event *event; unsigned long val[8]; int found, active; diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c index 4acaea01fe03..d35ae52c69dc 100644 --- a/arch/powerpc/perf/core-fsl-emb.c +++ b/arch/powerpc/perf/core-fsl-emb.c @@ -210,7 +210,7 @@ static void fsl_emb_pmu_disable(struct pmu *pmu) unsigned long flags; local_irq_save(flags); - cpuhw = this_cpu_ptr(&cpu_hw_events); + cpuhw = &__get_cpu_var(cpu_hw_events); if (!cpuhw->disabled) { cpuhw->disabled = 1; @@ -249,7 +249,7 @@ static void fsl_emb_pmu_enable(struct pmu *pmu) unsigned long flags; local_irq_save(flags); - cpuhw = this_cpu_ptr(&cpu_hw_events); + cpuhw = &__get_cpu_var(cpu_hw_events); if (!cpuhw->disabled) goto out; @@ -653,7 +653,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, static void perf_event_interrupt(struct pt_regs *regs) { int i; - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events); struct perf_event *event; unsigned long val; int found = 0; diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 4c11421847be..8a106b4172e0 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -82,7 +82,7 @@ static void iic_unmask(struct irq_data *d) static void iic_eoi(struct irq_data *d) { - struct iic *iic = this_cpu_ptr(&cpu_iic); + struct iic *iic = &__get_cpu_var(cpu_iic); out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]); BUG_ON(iic->eoi_ptr < 0); } @@ -148,7 +148,7 @@ static unsigned int iic_get_irq(void) struct iic *iic; unsigned int virq; - iic = this_cpu_ptr(&cpu_iic); + iic = &__get_cpu_var(cpu_iic); *(unsigned long *) &pending = in_be64((u64 __iomem *) &iic->regs->pending_destr); if (!(pending.flags & CBE_IIC_IRQ_VALID)) @@ -163,7 +163,7 @@ static unsigned int iic_get_irq(void) void iic_setup_cpu(void) { - out_be64(this_cpu_ptr(&cpu_iic.regs->prio), 0xff); + out_be64(&__get_cpu_var(cpu_iic).regs->prio, 0xff); } u8 iic_get_target_id(int cpu) diff --git a/arch/powerpc/platforms/powernv/opal-tracepoints.c b/arch/powerpc/platforms/powernv/opal-tracepoints.c index 9527e2a7c541..d8a000a9988b 100644 --- a/arch/powerpc/platforms/powernv/opal-tracepoints.c +++ b/arch/powerpc/platforms/powernv/opal-tracepoints.c @@ -48,7 +48,7 @@ void __trace_opal_entry(unsigned long opcode, unsigned long *args) local_irq_save(flags); - depth = this_cpu_ptr(&opal_trace_depth); + depth = &__get_cpu_var(opal_trace_depth); if (*depth) goto out; @@ -69,7 +69,7 @@ void __trace_opal_exit(long opcode, unsigned long retval) local_irq_save(flags); - depth = this_cpu_ptr(&opal_trace_depth); + depth = &__get_cpu_var(opal_trace_depth); if (*depth) goto out; diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index a6c42f34303a..5f3b23220b8e 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -711,7 +711,7 @@ void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq) static unsigned int ps3_get_irq(void) { - struct ps3_private *pd = this_cpu_ptr(&ps3_private); + struct ps3_private *pd = &__get_cpu_var(ps3_private); u64 x = (pd->bmp.status & pd->bmp.mask); unsigned int plug; diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index 39049e4884fb..1062f71f5a85 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -75,7 +75,7 @@ static atomic_t dtl_count; */ static void consume_dtle(struct dtl_entry *dtle, u64 index) { - struct dtl_ring *dtlr = this_cpu_ptr(&dtl_rings); + struct dtl_ring *dtlr = &__get_cpu_var(dtl_rings); struct dtl_entry *wp = dtlr->write_ptr; struct lppaca *vpa = local_paca->lppaca_ptr; diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index f02ec3ab428c..4575f0c9e521 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c @@ -110,7 +110,7 @@ static void probe_hcall_entry(void *ignored, unsigned long opcode, unsigned long if (opcode > MAX_HCALL_OPCODE) return; - h = this_cpu_ptr(&hcall_stats[opcode / 4]); + h = &__get_cpu_var(hcall_stats)[opcode / 4]; h->tb_start = mftb(); h->purr_start = mfspr(SPRN_PURR); } @@ -123,7 +123,7 @@ static void probe_hcall_exit(void *ignored, unsigned long opcode, unsigned long if (opcode > MAX_HCALL_OPCODE) return; - h = this_cpu_ptr(&hcall_stats[opcode / 4]); + h = &__get_cpu_var(hcall_stats)[opcode / 4]; h->num_calls++; h->tb_total += mftb() - h->tb_start; h->purr_total += mfspr(SPRN_PURR) - h->purr_start; diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 8c355ed4291e..4642d6a4d356 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -200,7 +200,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, local_irq_save(flags); /* to protect tcep and the page behind it */ - tcep = __this_cpu_read(tce_page); + tcep = __get_cpu_var(tce_page); /* This is safe to do since interrupts are off when we're called * from iommu_alloc{,_sg}() @@ -213,7 +213,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, direction, attrs); } - __this_cpu_write(tce_page, tcep); + __get_cpu_var(tce_page) = tcep; } rpn = __pa(uaddr) >> TCE_SHIFT; @@ -399,7 +399,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, long l, limit; local_irq_disable(); /* to protect tcep and the page behind it */ - tcep = __this_cpu_read(tce_page); + tcep = __get_cpu_var(tce_page); if (!tcep) { tcep = (__be64 *)__get_free_page(GFP_ATOMIC); @@ -407,7 +407,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, local_irq_enable(); return -ENOMEM; } - __this_cpu_write(tce_page, tcep); + __get_cpu_var(tce_page) = tcep; } proto_tce = TCE_PCI_READ | TCE_PCI_WRITE; diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 56df72da59fe..34e64237fff9 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -507,7 +507,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) unsigned long vpn; unsigned long i, pix, rc; unsigned long flags = 0; - struct ppc64_tlb_batch *batch = this_cpu_ptr(&ppc64_tlb_batch); + struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); unsigned long param[9]; unsigned long hash, index, shift, hidx, slot; @@ -697,7 +697,7 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args) local_irq_save(flags); - depth = this_cpu_ptr(&hcall_trace_depth); + depth = &__get_cpu_var(hcall_trace_depth); if (*depth) goto out; @@ -722,7 +722,7 @@ void __trace_hcall_exit(long opcode, unsigned long retval, local_irq_save(flags); - depth = this_cpu_ptr(&hcall_trace_depth); + depth = &__get_cpu_var(hcall_trace_depth); if (*depth) goto out; diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 179a69fd5568..dff05b9eb946 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -302,8 +302,8 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) /* If it isn't an extended log we can use the per cpu 64bit buffer */ h = (struct rtas_error_log *)&savep[1]; if (!rtas_error_extended(h)) { - memcpy(this_cpu_ptr(&mce_data_buf), h, sizeof(__u64)); - errhdr = (struct rtas_error_log *)this_cpu_ptr(&mce_data_buf); + memcpy(&__get_cpu_var(mce_data_buf), h, sizeof(__u64)); + errhdr = (struct rtas_error_log *)&__get_cpu_var(mce_data_buf); } else { int len, error_log_length; diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index 365249cd346b..fe0cca477164 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -155,7 +155,7 @@ int __init xics_smp_probe(void) void xics_teardown_cpu(void) { - struct xics_cppr *os_cppr = this_cpu_ptr(&xics_cppr); + struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); /* * we have to reset the cppr index to 0 because we're -- GitLab From 2d15d974618db4ed3adafe9b9fe092db0f5076a0 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Aug 2014 19:50:34 +0800 Subject: [PATCH 0715/5088] ASoC: rt5677: Add DMIC2 clock selection There are two pins can be used for rt5677's DMIC2 clock. This patch add the select options for it. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- include/sound/rt5677.h | 8 ++++++ sound/soc/codecs/rt5677.c | 57 +++++++++++++++++++++++++++++++++------ sound/soc/codecs/rt5677.h | 10 +++++++ 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h index 3da14313bcfc..a676717f74f4 100644 --- a/include/sound/rt5677.h +++ b/include/sound/rt5677.h @@ -12,10 +12,18 @@ #ifndef __LINUX_SND_RT5677_H #define __LINUX_SND_RT5677_H +enum rt5677_dmic2_clk { + RT5677_DMIC_CLK1 = 0, + RT5677_DMIC_CLK2 = 1, +}; + + struct rt5677_platform_data { /* IN1 IN2 can optionally be differential */ bool in1_diff; bool in2_diff; + /* DMIC2 clock source selection */ + enum rt5677_dmic2_clk dmic2_clk_pin; }; #endif diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 67f14556462f..f0b751bf1d6c 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -1700,14 +1700,19 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_INPUT("Haptic Generator"), - SND_SOC_DAPM_PGA("DMIC1", RT5677_DMIC_CTRL1, RT5677_DMIC_1_EN_SFT, 0, - NULL, 0), - SND_SOC_DAPM_PGA("DMIC2", RT5677_DMIC_CTRL1, RT5677_DMIC_2_EN_SFT, 0, - NULL, 0), - SND_SOC_DAPM_PGA("DMIC3", RT5677_DMIC_CTRL1, RT5677_DMIC_3_EN_SFT, 0, - NULL, 0), - SND_SOC_DAPM_PGA("DMIC4", RT5677_DMIC_CTRL2, RT5677_DMIC_4_EN_SFT, 0, - NULL, 0), + SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC4", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DMIC1 power", RT5677_DMIC_CTRL1, + RT5677_DMIC_1_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC2 power", RT5677_DMIC_CTRL1, + RT5677_DMIC_2_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC3 power", RT5677_DMIC_CTRL1, + RT5677_DMIC_3_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC4 power", RT5677_DMIC_CTRL2, + RT5677_DMIC_4_EN_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, set_dmic_clk, SND_SOC_DAPM_PRE_PMU), @@ -2130,6 +2135,13 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DMIC L4", NULL, "DMIC CLK" }, { "DMIC R4", NULL, "DMIC CLK" }, + { "DMIC L1", NULL, "DMIC1 power" }, + { "DMIC R1", NULL, "DMIC1 power" }, + { "DMIC L3", NULL, "DMIC3 power" }, + { "DMIC R3", NULL, "DMIC3 power" }, + { "DMIC L4", NULL, "DMIC4 power" }, + { "DMIC R4", NULL, "DMIC4 power" }, + { "BST1", NULL, "IN1P" }, { "BST1", NULL, "IN1N" }, { "BST2", NULL, "IN2P" }, @@ -2793,6 +2805,16 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "PDM2R", NULL, "PDM2 R Mux" }, }; +static const struct snd_soc_dapm_route rt5677_dmic2_clk_1[] = { + { "DMIC L2", NULL, "DMIC1 power" }, + { "DMIC R2", NULL, "DMIC1 power" }, +}; + +static const struct snd_soc_dapm_route rt5677_dmic2_clk_2[] = { + { "DMIC L2", NULL, "DMIC2 power" }, + { "DMIC R2", NULL, "DMIC2 power" }, +}; + static int rt5677_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { @@ -3144,6 +3166,16 @@ static int rt5677_probe(struct snd_soc_codec *codec) rt5677->codec = codec; + if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { + snd_soc_dapm_add_routes(&codec->dapm, + rt5677_dmic2_clk_2, + ARRAY_SIZE(rt5677_dmic2_clk_2)); + } else { /*use dmic1 clock by default*/ + snd_soc_dapm_add_routes(&codec->dapm, + rt5677_dmic2_clk_1, + ARRAY_SIZE(rt5677_dmic2_clk_1)); + } + rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF); regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); @@ -3381,6 +3413,15 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5677->regmap, RT5677_IN1, RT5677_IN_DF2, RT5677_IN_DF2); + if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { + regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2, + RT5677_GPIO5_FUNC_MASK, + RT5677_GPIO5_FUNC_DMIC); + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, + RT5677_GPIO5_DIR_MASK, + RT5677_GPIO5_DIR_OUT); + } + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, rt5677_dai, ARRAY_SIZE(rt5677_dai)); } diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 863393e62096..8791ab9637f3 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1363,6 +1363,11 @@ #define RT5677_SEL_SRC_IB01 (0x1 << 0) #define RT5677_SEL_SRC_IB01_SFT 0 +/* GPIO Control 2 (0xc1) */ +#define RT5677_GPIO5_DIR_MASK (0x1 << 14) +#define RT5677_GPIO5_DIR_IN (0x0 << 14) +#define RT5677_GPIO5_DIR_OUT (0x1 << 14) + /* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */ #define RT5677_DSP_IB_01_H (0x1 << 15) #define RT5677_DSP_IB_01_H_SFT 15 @@ -1393,6 +1398,11 @@ #define RT5677_DSP_IB_9_L (0x1 << 1) #define RT5677_DSP_IB_9_L_SFT 1 +/* General Control2 (0xfc)*/ +#define RT5677_GPIO5_FUNC_MASK (0x1 << 9) +#define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) +#define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) + /* System Clock Source */ enum { RT5677_SCLK_S_MCLK, -- GitLab From 13a7d299dbbcd4c76ff088ec240d7cd896174c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Sun, 24 Aug 2014 14:52:46 +0200 Subject: [PATCH 0716/5088] drm/radeon: move the IB test after the AGP fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise we won't test if the fallback to PCIe GART really worked. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_device.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index a5d202a7c0a4..b6aee40e6ef3 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1397,10 +1397,6 @@ int radeon_device_init(struct radeon_device *rdev, if (r) return r; - r = radeon_ib_ring_tests(rdev); - if (r) - DRM_ERROR("ib ring test failed (%d).\n", r); - r = radeon_gem_debugfs_init(rdev); if (r) { DRM_ERROR("registering gem debugfs failed (%d).\n", r); @@ -1418,6 +1414,10 @@ int radeon_device_init(struct radeon_device *rdev, return r; } + r = radeon_ib_ring_tests(rdev); + if (r) + DRM_ERROR("ib ring test failed (%d).\n", r); + if ((radeon_testing & 1)) { if (rdev->accel_working) radeon_test_moves(rdev); -- GitLab From b6a7eeeaa1cdf76f2522b75a2fd46280e8c3b3d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 16 Apr 2013 15:41:25 +0200 Subject: [PATCH 0717/5088] drm/radeon: force UVD buffers into VRAM on RS[78]80 v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: only necessary on RS[78]80 Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_cs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 0669399efcea..db739bd64f16 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -137,10 +137,13 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) + !!r->write_domain; /* the first reloc of an UVD job is the msg and that must be in - VRAM, also but everything into VRAM on AGP cards to avoid - image corruptions */ + VRAM, also but everything into VRAM on AGP cards and older + IGP chips to avoid image corruptions */ if (p->ring == R600_RING_TYPE_UVD_INDEX && - (i == 0 || drm_pci_device_is_agp(p->rdev->ddev))) { + (i == 0 || drm_pci_device_is_agp(p->rdev->ddev) || + p->rdev->family == CHIP_RS780 || + p->rdev->family == CHIP_RS880)) { + /* TODO: is this still needed for NI+ ? */ p->relocs[i].prefered_domains = RADEON_GEM_DOMAIN_VRAM; -- GitLab From a8fba64ab08cf4a5baf211f1126b475e03f90fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 25 Apr 2013 18:54:07 +0200 Subject: [PATCH 0718/5088] drm/radeon: properly init UVD MC bits on R600 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r600.c | 4 ++++ drivers/gpu/drm/radeon/r600d.h | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index e8bf0ea2dade..e7dca47b7196 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -992,6 +992,8 @@ static int r600_pcie_gart_enable(struct radeon_device *rdev) WREG32(MC_VM_L1_TLB_MCB_WR_GFX_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_RD_PDMA_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_WR_PDMA_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_UVD_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_UVD_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_RD_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE); WREG32(MC_VM_L1_TLB_MCB_WR_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE); WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12); @@ -1042,6 +1044,8 @@ static void r600_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_RD_UVD_CNTL, tmp); + WREG32(MC_VM_L1_TLB_MCB_WR_UVD_CNTL, tmp); radeon_gart_table_vram_unpin(rdev); } diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 0c4a7d8d93e0..3df030dc2352 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -334,7 +334,7 @@ #define MC_VM_AGP_BOT 0x2188 #define MC_VM_AGP_BASE 0x218C #define MC_VM_FB_LOCATION 0x2180 -#define MC_VM_L1_TLB_MCD_RD_A_CNTL 0x219C +#define MC_VM_L1_TLB_MCB_RD_UVD_CNTL 0x2124 #define ENABLE_L1_TLB (1 << 0) #define ENABLE_L1_FRAGMENT_PROCESSING (1 << 1) #define ENABLE_L1_STRICT_ORDERING (1 << 2) @@ -354,12 +354,14 @@ #define EFFECTIVE_L1_QUEUE_SIZE(x) (((x) & 7) << 15) #define EFFECTIVE_L1_QUEUE_SIZE_MASK 0x00038000 #define EFFECTIVE_L1_QUEUE_SIZE_SHIFT 15 +#define MC_VM_L1_TLB_MCD_RD_A_CNTL 0x219C #define MC_VM_L1_TLB_MCD_RD_B_CNTL 0x21A0 #define MC_VM_L1_TLB_MCB_RD_GFX_CNTL 0x21FC #define MC_VM_L1_TLB_MCB_RD_HDP_CNTL 0x2204 #define MC_VM_L1_TLB_MCB_RD_PDMA_CNTL 0x2208 #define MC_VM_L1_TLB_MCB_RD_SEM_CNTL 0x220C #define MC_VM_L1_TLB_MCB_RD_SYS_CNTL 0x2200 +#define MC_VM_L1_TLB_MCB_WR_UVD_CNTL 0x212c #define MC_VM_L1_TLB_MCD_WR_A_CNTL 0x21A4 #define MC_VM_L1_TLB_MCD_WR_B_CNTL 0x21A8 #define MC_VM_L1_TLB_MCB_WR_GFX_CNTL 0x2210 -- GitLab From 4a956a70a8d4cc5268a60f6718de58892fa1275e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 28 Nov 2012 16:55:21 -0500 Subject: [PATCH 0719/5088] drm/radeon: add set_uvd_clocks callback for r6xx v4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: wake up PLL, set [VD]CLK_SRC, cleanup code v3: handle RV670,RV635,RV620 as well v4: merge rv6xx and rs780/rs880 code, fix ref divider mask Signed-off-by: Alex Deucher Signed-off-by: Christian König --- drivers/gpu/drm/radeon/r600.c | 88 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/r600d.h | 26 ++++++++++ 2 files changed, 114 insertions(+) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index e7dca47b7196..011d97f6fc7f 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -122,6 +122,94 @@ u32 r600_get_xclk(struct radeon_device *rdev) int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk) { + unsigned fb_div = 0, ref_div, vclk_div = 0, dclk_div = 0; + int r; + + /* bypass vclk and dclk with bclk */ + WREG32_P(CG_UPLL_FUNC_CNTL_2, + VCLK_SRC_SEL(1) | DCLK_SRC_SEL(1), + ~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK)); + + /* assert BYPASS_EN, deassert UPLL_RESET, UPLL_SLEEP and UPLL_CTLREQ */ + WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~( + UPLL_RESET_MASK | UPLL_SLEEP_MASK | UPLL_CTLREQ_MASK)); + + if (rdev->family >= CHIP_RS780) + WREG32_P(GFX_MACRO_BYPASS_CNTL, UPLL_BYPASS_CNTL, + ~UPLL_BYPASS_CNTL); + + if (!vclk || !dclk) { + /* keep the Bypass mode, put PLL to sleep */ + WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK); + return 0; + } + + if (rdev->clock.spll.reference_freq == 10000) + ref_div = 34; + else + ref_div = 4; + + r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 50000, 160000, + ref_div + 1, 0xFFF, 2, 30, ~0, + &fb_div, &vclk_div, &dclk_div); + if (r) + return r; + + if (rdev->family >= CHIP_RV670 && rdev->family < CHIP_RS780) + fb_div >>= 1; + else + fb_div |= 1; + + r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL); + if (r) + return r; + + /* assert PLL_RESET */ + WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_RESET_MASK, ~UPLL_RESET_MASK); + + /* For RS780 we have to choose ref clk */ + if (rdev->family >= CHIP_RS780) + WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_REFCLK_SRC_SEL_MASK, + ~UPLL_REFCLK_SRC_SEL_MASK); + + /* set the required fb, ref and post divder values */ + WREG32_P(CG_UPLL_FUNC_CNTL, + UPLL_FB_DIV(fb_div) | + UPLL_REF_DIV(ref_div), + ~(UPLL_FB_DIV_MASK | UPLL_REF_DIV_MASK)); + WREG32_P(CG_UPLL_FUNC_CNTL_2, + UPLL_SW_HILEN(vclk_div >> 1) | + UPLL_SW_LOLEN((vclk_div >> 1) + (vclk_div & 1)) | + UPLL_SW_HILEN2(dclk_div >> 1) | + UPLL_SW_LOLEN2((dclk_div >> 1) + (dclk_div & 1)) | + UPLL_DIVEN_MASK | UPLL_DIVEN2_MASK, + ~UPLL_SW_MASK); + + /* give the PLL some time to settle */ + mdelay(15); + + /* deassert PLL_RESET */ + WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_RESET_MASK); + + mdelay(15); + + /* deassert BYPASS EN */ + WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK); + + if (rdev->family >= CHIP_RS780) + WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~UPLL_BYPASS_CNTL); + + r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL); + if (r) + return r; + + /* switch VCLK and DCLK selection */ + WREG32_P(CG_UPLL_FUNC_CNTL_2, + VCLK_SRC_SEL(2) | DCLK_SRC_SEL(2), + ~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK)); + + mdelay(100); + return 0; } diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 3df030dc2352..8c3fdd581a72 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -1526,9 +1526,35 @@ #define UVD_CONTEXT_ID 0xf6f4 +/* rs780 only */ +#define GFX_MACRO_BYPASS_CNTL 0x30c0 +#define SPLL_BYPASS_CNTL (1 << 0) +#define UPLL_BYPASS_CNTL (1 << 1) + +#define CG_UPLL_FUNC_CNTL 0x7e0 +# define UPLL_RESET_MASK 0x00000001 +# define UPLL_SLEEP_MASK 0x00000002 +# define UPLL_BYPASS_EN_MASK 0x00000004 # define UPLL_CTLREQ_MASK 0x00000008 +# define UPLL_FB_DIV(x) ((x) << 4) +# define UPLL_FB_DIV_MASK 0x0000FFF0 +# define UPLL_REF_DIV(x) ((x) << 16) +# define UPLL_REF_DIV_MASK 0x003F0000 +# define UPLL_REFCLK_SRC_SEL_MASK 0x20000000 # define UPLL_CTLACK_MASK 0x40000000 # define UPLL_CTLACK2_MASK 0x80000000 +#define CG_UPLL_FUNC_CNTL_2 0x7e4 +# define UPLL_SW_HILEN(x) ((x) << 0) +# define UPLL_SW_LOLEN(x) ((x) << 4) +# define UPLL_SW_HILEN2(x) ((x) << 8) +# define UPLL_SW_LOLEN2(x) ((x) << 12) +# define UPLL_DIVEN_MASK 0x00010000 +# define UPLL_DIVEN2_MASK 0x00020000 +# define UPLL_SW_MASK 0x0003FFFF +# define VCLK_SRC_SEL(x) ((x) << 20) +# define VCLK_SRC_SEL_MASK 0x01F00000 +# define DCLK_SRC_SEL(x) ((x) << 25) +# define DCLK_SRC_SEL_MASK 0x3E000000 /* * PM4 -- GitLab From 856754c3a23a622d26a82b29fab6429481705511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 16 Apr 2013 22:11:22 +0200 Subject: [PATCH 0720/5088] drm/radeon: add UVD support for older asics v4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: cleanup R600 support v3: rebased on current drm-fixes-3.12 v4: rebased on drm-next-3.14 Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r600.c | 31 +++++++++++ drivers/gpu/drm/radeon/r600d.h | 8 +++ drivers/gpu/drm/radeon/radeon_asic.c | 15 ++++++ drivers/gpu/drm/radeon/radeon_asic.h | 3 ++ drivers/gpu/drm/radeon/uvd_v1_0.c | 77 ++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/uvd_v2_2.c | 4 ++ 6 files changed, 138 insertions(+) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 011d97f6fc7f..14cb31e25c2f 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3009,6 +3009,17 @@ static int r600_startup(struct radeon_device *rdev) return r; } + r = uvd_v1_0_resume(rdev); + if (!r) { + r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); + } + } + if (r) { + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; + } + /* Enable IRQ */ if (!rdev->irq.installed) { r = radeon_irq_kms_init(rdev); @@ -3037,6 +3048,16 @@ static int r600_startup(struct radeon_device *rdev) if (r) return r; + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + if (ring->ring_size) { + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, + RADEON_CP_PACKET2); + if (!r) + r = uvd_v1_0_init(rdev); + if (r) + DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); + } + r = radeon_ib_pool_init(rdev); if (r) { dev_err(rdev->dev, "IB initialization failed (%d).\n", r); @@ -3096,6 +3117,8 @@ int r600_suspend(struct radeon_device *rdev) radeon_pm_suspend(rdev); r600_audio_fini(rdev); r600_cp_stop(rdev); + uvd_v1_0_fini(rdev); + radeon_uvd_suspend(rdev); r600_irq_suspend(rdev); radeon_wb_disable(rdev); r600_pcie_gart_disable(rdev); @@ -3175,6 +3198,12 @@ int r600_init(struct radeon_device *rdev) rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); + r = radeon_uvd_init(rdev); + if (!r) { + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); + } + rdev->ih.ring_obj = NULL; r600_ih_ring_init(rdev, 64 * 1024); @@ -3204,6 +3233,8 @@ void r600_fini(struct radeon_device *rdev) r600_audio_fini(rdev); r600_cp_fini(rdev); r600_irq_fini(rdev); + uvd_v1_0_fini(rdev); + radeon_uvd_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 8c3fdd581a72..420bed19e139 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -1485,6 +1485,7 @@ #define UVD_CGC_GATE 0xf4a8 #define UVD_LMI_CTRL2 0xf4f4 #define UVD_MASTINT_EN 0xf500 +#define UVD_FW_START 0xf51C #define UVD_LMI_ADDR_EXT 0xf594 #define UVD_LMI_CTRL 0xf598 #define UVD_LMI_SWAP_CNTL 0xf5b4 @@ -1497,6 +1498,13 @@ #define UVD_MPC_SET_MUX 0xf5f4 #define UVD_MPC_SET_ALU 0xf5f8 +#define UVD_VCPU_CACHE_OFFSET0 0xf608 +#define UVD_VCPU_CACHE_SIZE0 0xf60c +#define UVD_VCPU_CACHE_OFFSET1 0xf610 +#define UVD_VCPU_CACHE_SIZE1 0xf614 +#define UVD_VCPU_CACHE_OFFSET2 0xf618 +#define UVD_VCPU_CACHE_SIZE2 0xf61c + #define UVD_VCPU_CNTL 0xf660 #define UVD_SOFT_RESET 0xf680 #define RBC_SOFT_RESET (1<<0) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index eeeeabe09758..9e6699a9a0b4 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -965,6 +965,19 @@ static struct radeon_asic r600_asic = { }, }; +static struct radeon_asic_ring rv6xx_uvd_ring = { + .ib_execute = &uvd_v1_0_ib_execute, + .emit_fence = &uvd_v1_0_fence_emit, + .emit_semaphore = &uvd_v1_0_semaphore_emit, + .cs_parse = &radeon_uvd_cs_parse, + .ring_test = &uvd_v1_0_ring_test, + .ib_test = &uvd_v1_0_ib_test, + .is_lockup = &radeon_ring_test_lockup, + .get_rptr = &uvd_v1_0_get_rptr, + .get_wptr = &uvd_v1_0_get_wptr, + .set_wptr = &uvd_v1_0_set_wptr, +}; + static struct radeon_asic rv6xx_asic = { .init = &r600_init, .fini = &r600_fini, @@ -984,6 +997,7 @@ static struct radeon_asic rv6xx_asic = { .ring = { [RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring, [R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring, + [R600_RING_TYPE_UVD_INDEX] = &rv6xx_uvd_ring, }, .irq = { .set = &r600_irq_set, @@ -1074,6 +1088,7 @@ static struct radeon_asic rs780_asic = { .ring = { [RADEON_RING_TYPE_GFX_INDEX] = &r600_gfx_ring, [R600_RING_TYPE_DMA_INDEX] = &r600_dma_ring, + [R600_RING_TYPE_UVD_INDEX] = &rv6xx_uvd_ring, }, .irq = { .set = &r600_irq_set, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 275a5dc01780..987a3b713e06 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -883,6 +883,7 @@ uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev, struct radeon_ring *ring); void uvd_v1_0_set_wptr(struct radeon_device *rdev, struct radeon_ring *ring); +int uvd_v1_0_resume(struct radeon_device *rdev); int uvd_v1_0_init(struct radeon_device *rdev); void uvd_v1_0_fini(struct radeon_device *rdev); @@ -890,6 +891,8 @@ int uvd_v1_0_start(struct radeon_device *rdev); void uvd_v1_0_stop(struct radeon_device *rdev); int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); +void uvd_v1_0_fence_emit(struct radeon_device *rdev, + struct radeon_fence *fence); int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev, struct radeon_ring *ring, diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c index cda391347286..62d7086f0e08 100644 --- a/drivers/gpu/drm/radeon/uvd_v1_0.c +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c @@ -22,6 +22,7 @@ * Authors: Christian König */ +#include #include #include "radeon.h" #include "radeon_asic.h" @@ -69,6 +70,82 @@ void uvd_v1_0_set_wptr(struct radeon_device *rdev, WREG32(UVD_RBC_RB_WPTR, ring->wptr); } +/** + * uvd_v1_0_fence_emit - emit an fence & trap command + * + * @rdev: radeon_device pointer + * @fence: fence to emit + * + * Write a fence and a trap command to the ring. + */ +void uvd_v1_0_fence_emit(struct radeon_device *rdev, + struct radeon_fence *fence) +{ + struct radeon_ring *ring = &rdev->ring[fence->ring]; + uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; + + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); + radeon_ring_write(ring, addr & 0xffffffff); + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); + radeon_ring_write(ring, fence->seq); + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); + radeon_ring_write(ring, 0); + + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); + radeon_ring_write(ring, 2); + return; +} + +/** + * uvd_v1_0_resume - memory controller programming + * + * @rdev: radeon_device pointer + * + * Let the UVD memory controller know it's offsets + */ +int uvd_v1_0_resume(struct radeon_device *rdev) +{ + uint64_t addr; + uint32_t size; + int r; + + r = radeon_uvd_resume(rdev); + if (r) + return r; + + /* programm the VCPU memory controller bits 0-27 */ + addr = (rdev->uvd.gpu_addr >> 3) + 16; + size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size) >> 3; + WREG32(UVD_VCPU_CACHE_OFFSET0, addr); + WREG32(UVD_VCPU_CACHE_SIZE0, size); + + addr += size; + size = RADEON_UVD_STACK_SIZE >> 3; + WREG32(UVD_VCPU_CACHE_OFFSET1, addr); + WREG32(UVD_VCPU_CACHE_SIZE1, size); + + addr += size; + size = RADEON_UVD_HEAP_SIZE >> 3; + WREG32(UVD_VCPU_CACHE_OFFSET2, addr); + WREG32(UVD_VCPU_CACHE_SIZE2, size); + + /* bits 28-31 */ + addr = (rdev->uvd.gpu_addr >> 28) & 0xF; + WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0)); + + /* bits 32-39 */ + addr = (rdev->uvd.gpu_addr >> 32) & 0xFF; + WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31)); + + WREG32(UVD_FW_START, *((uint32_t*)rdev->uvd.cpu_addr)); + + return 0; +} + /** * uvd_v1_0_init - start and test UVD block * diff --git a/drivers/gpu/drm/radeon/uvd_v2_2.c b/drivers/gpu/drm/radeon/uvd_v2_2.c index 8bfdadd56598..89193519f8a1 100644 --- a/drivers/gpu/drm/radeon/uvd_v2_2.c +++ b/drivers/gpu/drm/radeon/uvd_v2_2.c @@ -72,6 +72,10 @@ int uvd_v2_2_resume(struct radeon_device *rdev) uint32_t chip_id, size; int r; + /* RV770 uses V1.0 MC */ + if (rdev->family == CHIP_RV770) + return uvd_v1_0_resume(rdev); + r = radeon_uvd_resume(rdev); if (r) return r; -- GitLab From 115365e8a33e4ce5e12bee7999568a26b4c33d3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 25 Apr 2013 09:02:14 +0200 Subject: [PATCH 0721/5088] drm/radeon: implement UVD hw workarounds for R6xx v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the essentials, cause this hw generation is really buggy. v2: start supporting RV670,RV620 and RV635 as well v3: activate more workarounds Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r600d.h | 3 +++ drivers/gpu/drm/radeon/uvd_v1_0.c | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 420bed19e139..671b48032a3d 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -330,6 +330,7 @@ #define HDP_TILING_CONFIG 0x2F3C #define HDP_DEBUG1 0x2F34 +#define MC_CONFIG 0x2000 #define MC_VM_AGP_TOP 0x2184 #define MC_VM_AGP_BOT 0x2188 #define MC_VM_AGP_BASE 0x218C @@ -375,6 +376,8 @@ #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2194 #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x2198 +#define RS_DQ_RD_RET_CONF 0x2348 + #define PA_CL_ENHANCE 0x8A14 #define CLIP_VTX_REORDER_ENA (1 << 0) #define NUM_CLIP_SEQ(x) ((x) << 1) diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c index 62d7086f0e08..c3e182bc6c59 100644 --- a/drivers/gpu/drm/radeon/uvd_v1_0.c +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c @@ -207,8 +207,32 @@ int uvd_v1_0_init(struct radeon_device *rdev) /* lower clocks again */ radeon_set_uvd_clocks(rdev, 0, 0); - if (!r) + if (!r) { + switch (rdev->family) { + case CHIP_RV610: + case CHIP_RV630: + case CHIP_RV620: + /* 64byte granularity workaround */ + WREG32(MC_CONFIG, 0); + WREG32(MC_CONFIG, 1 << 4); + WREG32(RS_DQ_RD_RET_CONF, 0x3f); + WREG32(MC_CONFIG, 0x1f); + + /* fall through */ + case CHIP_RV670: + case CHIP_RV635: + + /* write clean workaround */ + WREG32_P(UVD_VCPU_CNTL, 0x10, ~0x10); + break; + + default: + /* TODO: Do we need more? */ + break; + } + DRM_INFO("UVD initialized successfully.\n"); + } return r; } -- GitLab From bdc99722d007ed1db7188b09404bda080d1d737a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 26 Aug 2014 13:11:36 -0400 Subject: [PATCH 0722/5088] drm/radeon: 760G/780V/880V don't have UVD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't enable UVD on these asics as they don't have UVD hardware. Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/r600.c | 57 ++++++++++++++++------------ drivers/gpu/drm/radeon/radeon_asic.c | 10 ++++- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 14cb31e25c2f..a95ced569d84 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3009,15 +3009,16 @@ static int r600_startup(struct radeon_device *rdev) return r; } - r = uvd_v1_0_resume(rdev); - if (!r) { - r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); - if (r) { - dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); + if (rdev->has_uvd) { + r = uvd_v1_0_resume(rdev); + if (!r) { + r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); + if (r) { + dev_err(rdev->dev, "failed initializing UVD fences (%d).\n", r); + } } - } - if (r) { - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; + if (r) + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; } /* Enable IRQ */ @@ -3048,14 +3049,16 @@ static int r600_startup(struct radeon_device *rdev) if (r) return r; - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - if (ring->ring_size) { - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - RADEON_CP_PACKET2); - if (!r) - r = uvd_v1_0_init(rdev); - if (r) - DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); + if (rdev->has_uvd) { + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + if (ring->ring_size) { + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, + RADEON_CP_PACKET2); + if (!r) + r = uvd_v1_0_init(rdev); + if (r) + DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); + } } r = radeon_ib_pool_init(rdev); @@ -3117,8 +3120,10 @@ int r600_suspend(struct radeon_device *rdev) radeon_pm_suspend(rdev); r600_audio_fini(rdev); r600_cp_stop(rdev); - uvd_v1_0_fini(rdev); - radeon_uvd_suspend(rdev); + if (rdev->has_uvd) { + uvd_v1_0_fini(rdev); + radeon_uvd_suspend(rdev); + } r600_irq_suspend(rdev); radeon_wb_disable(rdev); r600_pcie_gart_disable(rdev); @@ -3198,10 +3203,12 @@ int r600_init(struct radeon_device *rdev) rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); - r = radeon_uvd_init(rdev); - if (!r) { - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; - r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); + if (rdev->has_uvd) { + r = radeon_uvd_init(rdev); + if (!r) { + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; + r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], 4096); + } } rdev->ih.ring_obj = NULL; @@ -3233,8 +3240,10 @@ void r600_fini(struct radeon_device *rdev) r600_audio_fini(rdev); r600_cp_fini(rdev); r600_irq_fini(rdev); - uvd_v1_0_fini(rdev); - radeon_uvd_fini(rdev); + if (rdev->has_uvd) { + uvd_v1_0_fini(rdev); + radeon_uvd_fini(rdev); + } radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 9e6699a9a0b4..d91f965e8219 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -2313,7 +2313,15 @@ int radeon_asic_init(struct radeon_device *rdev) case CHIP_RS780: case CHIP_RS880: rdev->asic = &rs780_asic; - rdev->has_uvd = true; + /* 760G/780V/880V don't have UVD */ + if ((rdev->pdev->device == 0x9616)|| + (rdev->pdev->device == 0x9611)|| + (rdev->pdev->device == 0x9613)|| + (rdev->pdev->device == 0x9711)|| + (rdev->pdev->device == 0x9713)) + rdev->has_uvd = false; + else + rdev->has_uvd = true; break; case CHIP_RV770: case CHIP_RV730: -- GitLab From 32517d59ebb3b6eb7a5a5736020072ce7e609e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 27 Aug 2014 09:59:45 +0200 Subject: [PATCH 0723/5088] drm/radeon: enable RB_ARB before resetting the VCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes "UVD not responding, trying to reset the VCPU" messages on earlier ASICs. Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/uvd_v1_0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c index c3e182bc6c59..e72b3cb59358 100644 --- a/drivers/gpu/drm/radeon/uvd_v1_0.c +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c @@ -319,12 +319,12 @@ int uvd_v1_0_start(struct radeon_device *rdev) /* enable UMC */ WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); + WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); + /* boot up the VCPU */ WREG32(UVD_SOFT_RESET, 0); mdelay(10); - WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); - for (i = 0; i < 10; ++i) { uint32_t status; for (j = 0; j < 100; ++j) { -- GitLab From 14e935aeb0213e2ef522d0d8a14d2d29fb194956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 16 Apr 2013 22:11:37 +0200 Subject: [PATCH 0724/5088] drm/radeon: add UVD fw names for older asic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Activating the UVD support. Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_uvd.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 341848a14376..a6ebaf0bda15 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -40,12 +40,18 @@ #define UVD_IDLE_TIMEOUT_MS 1000 /* Firmware Names */ +#define FIRMWARE_R600 "radeon/R600_uvd.bin" +#define FIRMWARE_RS780 "radeon/RS780_uvd.bin" +#define FIRMWARE_RV770 "radeon/RV770_uvd.bin" #define FIRMWARE_RV710 "radeon/RV710_uvd.bin" #define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin" #define FIRMWARE_SUMO "radeon/SUMO_uvd.bin" #define FIRMWARE_TAHITI "radeon/TAHITI_uvd.bin" #define FIRMWARE_BONAIRE "radeon/BONAIRE_uvd.bin" +MODULE_FIRMWARE(FIRMWARE_R600); +MODULE_FIRMWARE(FIRMWARE_RS780); +MODULE_FIRMWARE(FIRMWARE_RV770); MODULE_FIRMWARE(FIRMWARE_RV710); MODULE_FIRMWARE(FIRMWARE_CYPRESS); MODULE_FIRMWARE(FIRMWARE_SUMO); @@ -63,6 +69,23 @@ int radeon_uvd_init(struct radeon_device *rdev) INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler); switch (rdev->family) { + case CHIP_RV610: + case CHIP_RV630: + case CHIP_RV670: + case CHIP_RV620: + case CHIP_RV635: + fw_name = FIRMWARE_R600; + break; + + case CHIP_RS780: + case CHIP_RS880: + fw_name = FIRMWARE_RS780; + break; + + case CHIP_RV770: + fw_name = FIRMWARE_RV770; + break; + case CHIP_RV710: case CHIP_RV730: case CHIP_RV740: -- GitLab From f0d970b4fd05cb7af89307bb17689c18c835d739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 27 Aug 2014 15:21:53 +0200 Subject: [PATCH 0725/5088] drm/radeon: wake up all fences on manual reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wake up all fences when we manually trigger a reset. Signed-off-by: Christian König Reviewed-by: Maarten Lankhorst Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_fence.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 913787085dfa..5bd837afb939 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -833,6 +833,7 @@ static int radeon_debugfs_gpu_reset(struct seq_file *m, void *data) down_read(&rdev->exclusive_lock); seq_printf(m, "%d\n", rdev->needs_reset); rdev->needs_reset = true; + wake_up_all(&rdev->fence_queue); up_read(&rdev->exclusive_lock); return 0; -- GitLab From bf16d883263dedefb6149916e41b3e2779bb1573 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 25 Aug 2014 11:30:59 +0800 Subject: [PATCH 0726/5088] ASoC: fsl-asrc: Convert to use regmap framework's endianness method. Signed-off-by: Xiubo Li Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 822110420b71..3b145313f93e 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -684,7 +684,7 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_asrc_regmap_config = { +static const struct regmap_config fsl_asrc_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -802,10 +802,6 @@ static int fsl_asrc_probe(struct platform_device *pdev) asrc_priv->paddr = res->start; - /* Register regmap and let it prepare core clock */ - if (of_property_read_bool(np, "big-endian")) - fsl_asrc_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, &fsl_asrc_regmap_config); if (IS_ERR(asrc_priv->regmap)) { -- GitLab From 92bd0334b27845f250f1fadb091242140391c99b Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 25 Aug 2014 11:31:00 +0800 Subject: [PATCH 0727/5088] ASoC: fsl-esai: Convert to use regmap framework's endianness method. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 72d154e7dd03..2882fc66a10d 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -707,7 +707,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_esai_regmap_config = { +static const struct regmap_config fsl_esai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -733,9 +733,6 @@ static int fsl_esai_probe(struct platform_device *pdev) esai_priv->pdev = pdev; strcpy(esai_priv->name, np->name); - if (of_property_read_bool(np, "big-endian")) - fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); -- GitLab From 664915074e750614c5d140093d5098a165a24e3d Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 25 Aug 2014 11:31:01 +0800 Subject: [PATCH 0728/5088] ASoC: fsl-spdif: Convert to use regmap framework's endianness method. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 70acfe4a9bd5..ae4e408810ec 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1040,7 +1040,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_spdif_regmap_config = { +static const struct regmap_config fsl_spdif_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -1184,9 +1184,6 @@ static int fsl_spdif_probe(struct platform_device *pdev) memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); spdif_priv->cpu_dai_drv.name = spdif_priv->name; - if (of_property_read_bool(np, "big-endian")) - fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); -- GitLab From 014fd22ef9c6a7e9536b7e16635714a1a34810a8 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 25 Aug 2014 11:31:02 +0800 Subject: [PATCH 0729/5088] ASoC: fsl-sai: Convert to use regmap framework's endianness method. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl-sai.txt | 7 +++---- sound/soc/fsl/fsl_sai.c | 6 +----- sound/soc/fsl/fsl_sai.h | 1 - 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 0f4e23828190..5f239b8bcddd 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -18,9 +18,8 @@ Required properties: - pinctrl-names: Must contain a "default" entry. - pinctrl-NNN: One property must exist for each entry in pinctrl-names. See ../pinctrl/pinctrl-bindings.txt for details of the property values. -- big-endian-regs: If this property is absent, the little endian mode will - be in use as default, or the big endian mode will be in use for all the - device registers. +- big-endian: Boolean property, required if all the FTM_PWM registers + are big-endian rather than little-endian. - big-endian-data: If this property is absent, the little endian mode will be in use as default, or the big endian mode will be in use for all the fifo data. @@ -38,6 +37,6 @@ sai2: sai@40031000 { dma-names = "tx", "rx"; dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>, <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>; - big-endian-regs; + big-endian; big-endian-data; }; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index faa049797897..52d1e9982639 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -539,7 +539,7 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_sai_regmap_config = { +static const struct regmap_config fsl_sai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -568,10 +568,6 @@ static int fsl_sai_probe(struct platform_device *pdev) if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai")) sai->sai_on_imx = true; - sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); - if (sai->big_endian_regs) - fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 0e6c9f595d75..20e3e53ce6ea 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -131,7 +131,6 @@ struct fsl_sai { struct clk *bus_clk; struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; - bool big_endian_regs; bool big_endian_data; bool is_dsp_mode; bool sai_on_imx; -- GitLab From eb98c709907c7a78b9cd0d18642477d47d348f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 27 Aug 2014 15:21:56 +0200 Subject: [PATCH 0730/5088] drm/radeon: force fence completion only on problematic rings (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of resetting all fence numbers, only reset the number of the problematic ring. Split out from a patch from Maarten Lankhorst v2 (agd5f): rebase build fix Signed-off-by: Christian König Reviewed-by: Maarten Lankhorst Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 2 +- drivers/gpu/drm/radeon/radeon_device.c | 8 ++------ drivers/gpu/drm/radeon/radeon_fence.c | 12 ++++-------- drivers/gpu/drm/radeon/radeon_ib.c | 1 + 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b321ad4dcafd..5f967c0b5aa3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -371,7 +371,7 @@ struct radeon_fence { int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring); int radeon_fence_driver_init(struct radeon_device *rdev); void radeon_fence_driver_fini(struct radeon_device *rdev); -void radeon_fence_driver_force_completion(struct radeon_device *rdev); +void radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring); int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring); void radeon_fence_process(struct radeon_device *rdev, int ring); bool radeon_fence_signaled(struct radeon_fence *fence); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index b6aee40e6ef3..8b442e4ab1da 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1488,7 +1488,6 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) struct drm_crtc *crtc; struct drm_connector *connector; int i, r; - bool force_completion = false; if (dev == NULL || dev->dev_private == NULL) { return -ENODEV; @@ -1532,12 +1531,9 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) r = radeon_fence_wait_empty(rdev, i); if (r) { /* delay GPU reset to resume */ - force_completion = true; + radeon_fence_driver_force_completion(rdev, i); } } - if (force_completion) { - radeon_fence_driver_force_completion(rdev); - } radeon_save_bios_scratch_regs(rdev); @@ -1722,8 +1718,8 @@ int radeon_gpu_reset(struct radeon_device *rdev) } } } else { - radeon_fence_driver_force_completion(rdev); for (i = 0; i < RADEON_NUM_RINGS; ++i) { + radeon_fence_driver_force_completion(rdev, i); kfree(ring_data[i]); } } diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 5bd837afb939..e8a28e7b39c7 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -758,7 +758,7 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) r = radeon_fence_wait_empty(rdev, ring); if (r) { /* no need to trigger GPU reset as we are unloading */ - radeon_fence_driver_force_completion(rdev); + radeon_fence_driver_force_completion(rdev, ring); } wake_up_all(&rdev->fence_queue); radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); @@ -771,19 +771,15 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) * radeon_fence_driver_force_completion - force all fence waiter to complete * * @rdev: radeon device pointer + * @ring: the ring to complete * * In case of GPU reset failure make sure no process keep waiting on fence * that will never complete. */ -void radeon_fence_driver_force_completion(struct radeon_device *rdev) +void radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring) { - int ring; - - for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { - if (!rdev->fence_drv[ring].initialized) - continue; + if (rdev->fence_drv[ring].initialized) radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring); - } } diff --git a/drivers/gpu/drm/radeon/radeon_ib.c b/drivers/gpu/drm/radeon/radeon_ib.c index 5bf2c0a05827..6fc7461d70c4 100644 --- a/drivers/gpu/drm/radeon/radeon_ib.c +++ b/drivers/gpu/drm/radeon/radeon_ib.c @@ -269,6 +269,7 @@ int radeon_ib_ring_tests(struct radeon_device *rdev) r = radeon_ib_test(rdev, i, ring); if (r) { + radeon_fence_driver_force_completion(rdev, i); ring->ready = false; rdev->needs_reset = false; -- GitLab From 06cb1eb3de5c905da60ab91dbf99aaf96a43d043 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 21 Aug 2014 18:20:49 +0530 Subject: [PATCH 0731/5088] ASoC: mfld-compress: Use dedicated function instead of ioctl Also pass sst device as an argument to function pointer prototypes of compr_ops. This will be used to derive sst driver context. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-compress.c | 38 +++++++++++++++----- sound/soc/intel/sst-mfld-platform.h | 27 ++++++++------ 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c index 29c059ca19e8..59467775c9b8 100644 --- a/sound/soc/intel/sst-mfld-platform-compress.c +++ b/sound/soc/intel/sst-mfld-platform-compress.c @@ -86,7 +86,7 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream) /*need to check*/ str_id = stream->id; if (str_id) - ret_val = stream->compr_ops->close(str_id); + ret_val = stream->compr_ops->close(sst->dev, str_id); module_put(sst->dev->driver->owner); kfree(stream); pr_debug("%s: %d\n", __func__, ret_val); @@ -158,7 +158,7 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, cb.drain_cb_param = cstream; cb.drain_notify = sst_drain_notify; - retval = stream->compr_ops->open(&str_params, &cb); + retval = stream->compr_ops->open(sst->dev, &str_params, &cb); if (retval < 0) { pr_err("stream allocation failed %d\n", retval); return retval; @@ -170,10 +170,30 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) { - struct sst_runtime_stream *stream = - cstream->runtime->private_data; - - return stream->compr_ops->control(cmd, stream->id); + struct sst_runtime_stream *stream = cstream->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (stream->compr_ops->stream_start) + return stream->compr_ops->stream_start(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_STOP: + if (stream->compr_ops->stream_drop) + return stream->compr_ops->stream_drop(sst->dev, stream->id); + case SND_COMPR_TRIGGER_DRAIN: + if (stream->compr_ops->stream_drain) + return stream->compr_ops->stream_drain(sst->dev, stream->id); + case SND_COMPR_TRIGGER_PARTIAL_DRAIN: + if (stream->compr_ops->stream_partial_drain) + return stream->compr_ops->stream_partial_drain(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (stream->compr_ops->stream_pause) + return stream->compr_ops->stream_pause(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (stream->compr_ops->stream_pause_release) + return stream->compr_ops->stream_pause_release(sst->dev, stream->id); + default: + return -EINVAL; + } } static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, @@ -182,7 +202,7 @@ static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream; stream = cstream->runtime->private_data; - stream->compr_ops->tstamp(stream->id, tstamp); + stream->compr_ops->tstamp(sst->dev, stream->id, tstamp); tstamp->byte_offset = tstamp->copied_total % (u32)cstream->runtime->buffer_size; pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); @@ -195,7 +215,7 @@ static int sst_platform_compr_ack(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream; stream = cstream->runtime->private_data; - stream->compr_ops->ack(stream->id, (unsigned long)bytes); + stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes); stream->bytes_written += bytes; return 0; @@ -225,7 +245,7 @@ static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream = cstream->runtime->private_data; - return stream->compr_ops->set_metadata(stream->id, metadata); + return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata); } struct snd_compr_ops sst_platform_compr_ops = { diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index faaba10c1dff..0c5b943daff3 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -99,17 +99,24 @@ struct sst_compress_cb { struct compress_sst_ops { const char *name; - int (*open) (struct snd_sst_params *str_params, - struct sst_compress_cb *cb); - int (*control) (unsigned int cmd, unsigned int str_id); - int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp); - int (*ack) (unsigned int str_id, unsigned long bytes); - int (*close) (unsigned int str_id); - int (*get_caps) (struct snd_compr_caps *caps); - int (*get_codec_caps) (struct snd_compr_codec_caps *codec); - int (*set_metadata) (unsigned int str_id, + int (*open)(struct device *dev, + struct snd_sst_params *str_params, struct sst_compress_cb *cb); + int (*stream_start)(struct device *dev, unsigned int str_id); + int (*stream_drop)(struct device *dev, unsigned int str_id); + int (*stream_drain)(struct device *dev, unsigned int str_id); + int (*stream_partial_drain)(struct device *dev, unsigned int str_id); + int (*stream_pause)(struct device *dev, unsigned int str_id); + int (*stream_pause_release)(struct device *dev, unsigned int str_id); + + int (*tstamp)(struct device *dev, unsigned int str_id, + struct snd_compr_tstamp *tstamp); + int (*ack)(struct device *dev, unsigned int str_id, + unsigned long bytes); + int (*close)(struct device *dev, unsigned int str_id); + int (*get_caps)(struct snd_compr_caps *caps); + int (*get_codec_caps)(struct snd_compr_codec_caps *codec); + int (*set_metadata)(struct device *dev, unsigned int str_id, struct snd_compr_metadata *mdata); - }; struct sst_ops { -- GitLab From 9bb39ff43e15e85bc1bd9bbbdc5b9cef7a670fd5 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 27 Aug 2014 16:45:18 -0400 Subject: [PATCH 0732/5088] drm/radeon: take exclusive_lock in read mode during ring tests, v5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is needed for the next commit, because the lockup detection will need the read lock to run. v4 (chk): split out forced fence completion, remove unrelated changes, add and handle in_reset flag v5 (agd5f): rebase fix Signed-off-by: Maarten Lankhorst Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 2 +- drivers/gpu/drm/radeon/radeon_cs.c | 7 +++++ drivers/gpu/drm/radeon/radeon_device.c | 37 +++++++++++-------------- drivers/gpu/drm/radeon/radeon_display.c | 4 ++- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5f967c0b5aa3..8cd1b3f60d4a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -2326,7 +2326,7 @@ struct radeon_device { bool need_dma32; bool accel_working; bool fastfb_working; /* IGP feature*/ - bool needs_reset; + bool needs_reset, in_reset; struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES]; const struct firmware *me_fw; /* all family ME firmware */ const struct firmware *pfp_fw; /* r6/700 PFP firmware */ diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index db739bd64f16..bd328cb6fa61 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -653,6 +653,13 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) up_read(&rdev->exclusive_lock); return -EBUSY; } + if (rdev->in_reset) { + up_read(&rdev->exclusive_lock); + r = radeon_gpu_reset(rdev); + if (!r) + r = -EAGAIN; + return r; + } /* initialize parser */ memset(&parser, 0, sizeof(struct radeon_cs_parser)); parser.filp = filp; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 8b442e4ab1da..9f666370b5ac 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1673,6 +1673,7 @@ int radeon_gpu_reset(struct radeon_device *rdev) return 0; } + rdev->in_reset = true; rdev->needs_reset = false; radeon_save_bios_scratch_regs(rdev); @@ -1691,7 +1692,6 @@ int radeon_gpu_reset(struct radeon_device *rdev) } } -retry: r = radeon_asic_reset(rdev); if (!r) { dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n"); @@ -1700,25 +1700,11 @@ int radeon_gpu_reset(struct radeon_device *rdev) radeon_restore_bios_scratch_regs(rdev); - if (!r) { - for (i = 0; i < RADEON_NUM_RINGS; ++i) { + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + if (!r && ring_data[i]) { radeon_ring_restore(rdev, &rdev->ring[i], ring_sizes[i], ring_data[i]); - ring_sizes[i] = 0; - ring_data[i] = NULL; - } - - r = radeon_ib_ring_tests(rdev); - if (r) { - dev_err(rdev->dev, "ib ring test failed (%d).\n", r); - if (saved) { - saved = false; - radeon_suspend(rdev); - goto retry; - } - } - } else { - for (i = 0; i < RADEON_NUM_RINGS; ++i) { + } else { radeon_fence_driver_force_completion(rdev, i); kfree(ring_data[i]); } @@ -1751,19 +1737,28 @@ int radeon_gpu_reset(struct radeon_device *rdev) /* reset hpd state */ radeon_hpd_init(rdev); + ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); + downgrade_write(&rdev->exclusive_lock); + drm_helper_resume_force_mode(rdev->ddev); /* set the power state here in case we are a PX system or headless */ if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) radeon_pm_compute_clocks(rdev); - ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); - if (r) { + if (!r) { + r = radeon_ib_ring_tests(rdev); + if (r && saved) + r = -EAGAIN; + } else { /* bad news, how to tell it to userspace ? */ dev_info(rdev->dev, "GPU reset failed\n"); } - up_write(&rdev->exclusive_lock); + rdev->needs_reset = r == -EAGAIN; + rdev->in_reset = false; + + up_read(&rdev->exclusive_lock); return r; } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 3fdf87318069..bd0d687379ee 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -405,7 +405,9 @@ static void radeon_flip_work_func(struct work_struct *__work) r = radeon_fence_wait(work->fence, false); if (r == -EDEADLK) { up_read(&rdev->exclusive_lock); - r = radeon_gpu_reset(rdev); + do { + r = radeon_gpu_reset(rdev); + } while (r == -EAGAIN); down_read(&rdev->exclusive_lock); } if (r) -- GitLab From 0bfa4b41268ad5fd741f16f484e4fee190822ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 27 Aug 2014 15:21:58 +0200 Subject: [PATCH 0733/5088] drm/radeon: handle lockup in delayed work, v5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v5 (chk): complete rework, start when the first fence is emitted, stop when the last fence is signalled, make it work correctly with GPU resets, cleanup radeon_fence_wait_seq Signed-off-by: Maarten Lankhorst Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 2 + drivers/gpu/drm/radeon/radeon_fence.c | 200 ++++++++++++++++---------- 2 files changed, 124 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 8cd1b3f60d4a..74919ef57ac3 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -350,6 +350,7 @@ extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw, * Fences. */ struct radeon_fence_driver { + struct radeon_device *rdev; uint32_t scratch_reg; uint64_t gpu_addr; volatile uint32_t *cpu_addr; @@ -357,6 +358,7 @@ struct radeon_fence_driver { uint64_t sync_seq[RADEON_NUM_RINGS]; atomic64_t last_seq; bool initialized; + struct delayed_work lockup_work; }; struct radeon_fence { diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index e8a28e7b39c7..ac15f3418478 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -97,6 +97,25 @@ static u32 radeon_fence_read(struct radeon_device *rdev, int ring) return seq; } +/** + * radeon_fence_schedule_check - schedule lockup check + * + * @rdev: radeon_device pointer + * @ring: ring index we should work with + * + * Queues a delayed work item to check for lockups. + */ +static void radeon_fence_schedule_check(struct radeon_device *rdev, int ring) +{ + /* + * Do not reset the timer here with mod_delayed_work, + * this can livelock in an interaction with TTM delayed destroy. + */ + queue_delayed_work(system_power_efficient_wq, + &rdev->fence_drv[ring].lockup_work, + RADEON_FENCE_JIFFIES_TIMEOUT); +} + /** * radeon_fence_emit - emit a fence on the requested ring * @@ -122,19 +141,21 @@ int radeon_fence_emit(struct radeon_device *rdev, (*fence)->ring = ring; radeon_fence_ring_emit(rdev, ring, *fence); trace_radeon_fence_emit(rdev->ddev, ring, (*fence)->seq); + radeon_fence_schedule_check(rdev, ring); return 0; } /** - * radeon_fence_process - process a fence + * radeon_fence_activity - check for fence activity * * @rdev: radeon_device pointer * @ring: ring index the fence is associated with * - * Checks the current fence value and wakes the fence queue - * if the sequence number has increased (all asics). + * Checks the current fence value and calculates the last + * signalled fence value. Returns true if activity occured + * on the ring, and the fence_queue should be waken up. */ -void radeon_fence_process(struct radeon_device *rdev, int ring) +static bool radeon_fence_activity(struct radeon_device *rdev, int ring) { uint64_t seq, last_seq, last_emitted; unsigned count_loop = 0; @@ -190,7 +211,67 @@ void radeon_fence_process(struct radeon_device *rdev, int ring) } } while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq); - if (wake) + if (seq < last_emitted) + radeon_fence_schedule_check(rdev, ring); + + return wake; +} + +/** + * radeon_fence_check_lockup - check for hardware lockup + * + * @work: delayed work item + * + * Checks for fence activity and if there is none probe + * the hardware if a lockup occured. + */ +static void radeon_fence_check_lockup(struct work_struct *work) +{ + struct radeon_fence_driver *fence_drv; + struct radeon_device *rdev; + int ring; + + fence_drv = container_of(work, struct radeon_fence_driver, + lockup_work.work); + rdev = fence_drv->rdev; + ring = fence_drv - &rdev->fence_drv[0]; + + if (!down_read_trylock(&rdev->exclusive_lock)) { + /* just reschedule the check if a reset is going on */ + radeon_fence_schedule_check(rdev, ring); + return; + } + + if (radeon_fence_activity(rdev, ring)) + wake_up_all(&rdev->fence_queue); + + else if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) { + + /* good news we believe it's a lockup */ + dev_warn(rdev->dev, "GPU lockup (current fence id " + "0x%016llx last fence id 0x%016llx on ring %d)\n", + (uint64_t)atomic64_read(&fence_drv->last_seq), + fence_drv->sync_seq[ring], ring); + + /* remember that we need an reset */ + rdev->needs_reset = true; + wake_up_all(&rdev->fence_queue); + } + up_read(&rdev->exclusive_lock); +} + +/** + * radeon_fence_process - process a fence + * + * @rdev: radeon_device pointer + * @ring: ring index the fence is associated with + * + * Checks the current fence value and wakes the fence queue + * if the sequence number has increased (all asics). + */ +void radeon_fence_process(struct radeon_device *rdev, int ring) +{ + if (radeon_fence_activity(rdev, ring)) wake_up_all(&rdev->fence_queue); } @@ -300,86 +381,43 @@ static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq) static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq, bool intr) { - uint64_t last_seq[RADEON_NUM_RINGS]; - bool signaled; - int i, r; - - while (!radeon_fence_any_seq_signaled(rdev, target_seq)) { + long r; + int i; - /* Save current sequence values, used to check for GPU lockups */ - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - if (!target_seq[i]) - continue; + if (radeon_fence_any_seq_signaled(rdev, target_seq)) + return 0; - last_seq[i] = atomic64_read(&rdev->fence_drv[i].last_seq); - trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]); - radeon_irq_kms_sw_irq_get(rdev, i); - } + /* enable IRQs and tracing */ + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + if (!target_seq[i]) + continue; - if (intr) { - r = wait_event_interruptible_timeout(rdev->fence_queue, ( - (signaled = radeon_fence_any_seq_signaled(rdev, target_seq)) - || rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT); - } else { - r = wait_event_timeout(rdev->fence_queue, ( - (signaled = radeon_fence_any_seq_signaled(rdev, target_seq)) - || rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT); - } + trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]); + radeon_irq_kms_sw_irq_get(rdev, i); + } - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - if (!target_seq[i]) - continue; + if (intr) { + r = wait_event_interruptible_timeout(rdev->fence_queue, ( + radeon_fence_any_seq_signaled(rdev, target_seq) + || rdev->needs_reset), MAX_SCHEDULE_TIMEOUT); + } else { + r = wait_event_timeout(rdev->fence_queue, ( + radeon_fence_any_seq_signaled(rdev, target_seq) + || rdev->needs_reset), MAX_SCHEDULE_TIMEOUT); + } - radeon_irq_kms_sw_irq_put(rdev, i); - trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]); - } + if (rdev->needs_reset) + r = -EDEADLK; - if (unlikely(r < 0)) - return r; + for (i = 0; i < RADEON_NUM_RINGS; ++i) { + if (!target_seq[i]) + continue; - if (unlikely(!signaled)) { - if (rdev->needs_reset) - return -EDEADLK; - - /* we were interrupted for some reason and fence - * isn't signaled yet, resume waiting */ - if (r) - continue; - - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - if (!target_seq[i]) - continue; - - if (last_seq[i] != atomic64_read(&rdev->fence_drv[i].last_seq)) - break; - } - - if (i != RADEON_NUM_RINGS) - continue; - - for (i = 0; i < RADEON_NUM_RINGS; ++i) { - if (!target_seq[i]) - continue; - - if (radeon_ring_is_lockup(rdev, i, &rdev->ring[i])) - break; - } - - if (i < RADEON_NUM_RINGS) { - /* good news we believe it's a lockup */ - dev_warn(rdev->dev, "GPU lockup (waiting for " - "0x%016llx last fence id 0x%016llx on" - " ring %d)\n", - target_seq[i], last_seq[i], i); - - /* remember that we need an reset */ - rdev->needs_reset = true; - wake_up_all(&rdev->fence_queue); - return -EDEADLK; - } - } + radeon_irq_kms_sw_irq_put(rdev, i); + trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]); } - return 0; + + return r < 0 ? r : 0; } /** @@ -711,6 +749,9 @@ static void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring) rdev->fence_drv[ring].sync_seq[i] = 0; atomic64_set(&rdev->fence_drv[ring].last_seq, 0); rdev->fence_drv[ring].initialized = false; + INIT_DELAYED_WORK(&rdev->fence_drv[ring].lockup_work, + radeon_fence_check_lockup); + rdev->fence_drv[ring].rdev = rdev; } /** @@ -760,6 +801,7 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) /* no need to trigger GPU reset as we are unloading */ radeon_fence_driver_force_completion(rdev, ring); } + cancel_delayed_work_sync(&rdev->fence_drv[ring].lockup_work); wake_up_all(&rdev->fence_queue); radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); rdev->fence_drv[ring].initialized = false; @@ -778,8 +820,10 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) */ void radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring) { - if (rdev->fence_drv[ring].initialized) + if (rdev->fence_drv[ring].initialized) { radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring); + cancel_delayed_work_sync(&rdev->fence_drv[ring].lockup_work); + } } -- GitLab From 9867d00dbaef42e346e5d12eaa9591b057fea6d8 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 27 Aug 2014 15:21:59 +0200 Subject: [PATCH 0734/5088] drm/radeon: add timeout argument to radeon_fence_wait_seq v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it possible to wait for a specific amount of time, rather than wait until infinity. v2 (chk): rebased on other changes Signed-off-by: Maarten Lankhorst Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_fence.c | 48 ++++++++++++++++----------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index ac15f3418478..a54bfd60510b 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -364,28 +364,31 @@ static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq) } /** - * radeon_fence_wait_seq - wait for a specific sequence numbers + * radeon_fence_wait_seq_timeout - wait for a specific sequence numbers * * @rdev: radeon device pointer * @target_seq: sequence number(s) we want to wait for * @intr: use interruptable sleep + * @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite wait * * Wait for the requested sequence number(s) to be written by any ring * (all asics). Sequnce number array is indexed by ring id. * @intr selects whether to use interruptable (true) or non-interruptable * (false) sleep when waiting for the sequence number. Helper function * for radeon_fence_wait_*(). - * Returns 0 if the sequence number has passed, error for all other cases. + * Returns remaining time if the sequence number has passed, 0 when + * the wait timeout, or an error for all other cases. * -EDEADLK is returned when a GPU lockup has been detected. */ -static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq, - bool intr) +static long radeon_fence_wait_seq_timeout(struct radeon_device *rdev, + u64 *target_seq, bool intr, + long timeout) { long r; int i; if (radeon_fence_any_seq_signaled(rdev, target_seq)) - return 0; + return timeout; /* enable IRQs and tracing */ for (i = 0; i < RADEON_NUM_RINGS; ++i) { @@ -399,11 +402,11 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq, if (intr) { r = wait_event_interruptible_timeout(rdev->fence_queue, ( radeon_fence_any_seq_signaled(rdev, target_seq) - || rdev->needs_reset), MAX_SCHEDULE_TIMEOUT); + || rdev->needs_reset), timeout); } else { r = wait_event_timeout(rdev->fence_queue, ( radeon_fence_any_seq_signaled(rdev, target_seq) - || rdev->needs_reset), MAX_SCHEDULE_TIMEOUT); + || rdev->needs_reset), timeout); } if (rdev->needs_reset) @@ -417,14 +420,14 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq, trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]); } - return r < 0 ? r : 0; + return r; } /** * radeon_fence_wait - wait for a fence to signal * * @fence: radeon fence object - * @intr: use interruptable sleep + * @intr: use interruptible sleep * * Wait for the requested fence to signal (all asics). * @intr selects whether to use interruptable (true) or non-interruptable @@ -434,7 +437,7 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq, int radeon_fence_wait(struct radeon_fence *fence, bool intr) { uint64_t seq[RADEON_NUM_RINGS] = {}; - int r; + long r; if (fence == NULL) { WARN(1, "Querying an invalid fence : %p !\n", fence); @@ -445,9 +448,10 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr) if (seq[fence->ring] == RADEON_FENCE_SIGNALED_SEQ) return 0; - r = radeon_fence_wait_seq(fence->rdev, seq, intr); - if (r) + r = radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, MAX_SCHEDULE_TIMEOUT); + if (r < 0) { return r; + } fence->seq = RADEON_FENCE_SIGNALED_SEQ; return 0; @@ -472,7 +476,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev, { uint64_t seq[RADEON_NUM_RINGS]; unsigned i, num_rings = 0; - int r; + long r; for (i = 0; i < RADEON_NUM_RINGS; ++i) { seq[i] = 0; @@ -493,8 +497,8 @@ int radeon_fence_wait_any(struct radeon_device *rdev, if (num_rings == 0) return -ENOENT; - r = radeon_fence_wait_seq(rdev, seq, intr); - if (r) { + r = radeon_fence_wait_seq_timeout(rdev, seq, intr, MAX_SCHEDULE_TIMEOUT); + if (r < 0) { return r; } return 0; @@ -513,6 +517,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev, int radeon_fence_wait_next(struct radeon_device *rdev, int ring) { uint64_t seq[RADEON_NUM_RINGS] = {}; + long r; seq[ring] = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL; if (seq[ring] >= rdev->fence_drv[ring].sync_seq[ring]) { @@ -520,7 +525,10 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring) already the last emited fence */ return -ENOENT; } - return radeon_fence_wait_seq(rdev, seq, false); + r = radeon_fence_wait_seq_timeout(rdev, seq, false, MAX_SCHEDULE_TIMEOUT); + if (r < 0) + return r; + return 0; } /** @@ -536,18 +544,18 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring) int radeon_fence_wait_empty(struct radeon_device *rdev, int ring) { uint64_t seq[RADEON_NUM_RINGS] = {}; - int r; + long r; seq[ring] = rdev->fence_drv[ring].sync_seq[ring]; if (!seq[ring]) return 0; - r = radeon_fence_wait_seq(rdev, seq, false); - if (r) { + r = radeon_fence_wait_seq_timeout(rdev, seq, false, MAX_SCHEDULE_TIMEOUT); + if (r < 0) { if (r == -EDEADLK) return -EDEADLK; - dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n", + dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%ld)\n", ring, r); } return 0; -- GitLab From d6d5c5b8364bcc4d52cddc68bcb0a330d2af20f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 27 Aug 2014 15:22:00 +0200 Subject: [PATCH 0735/5088] drm/radeon: drop RADEON_FENCE_SIGNALED_SEQ v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's causing issues with VMID handling and comparing the fence value two times actually doesn't make handling faster. v2: rebased on reset changes Signed-off-by: Christian König Reviewed-by: Maarten Lankhorst Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 3 --- drivers/gpu/drm/radeon/radeon_fence.c | 18 ++---------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 74919ef57ac3..896a84779650 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -120,9 +120,6 @@ extern int radeon_bapm; #define RADEONFB_CONN_LIMIT 4 #define RADEON_BIOS_NUM_SCRATCH 8 -/* fence seq are set to this number when signaled */ -#define RADEON_FENCE_SIGNALED_SEQ 0LL - /* internal ring indices */ /* r1xx+ has gfx CP ring */ #define RADEON_RING_TYPE_GFX_INDEX 0 diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index a54bfd60510b..ecdba3afa2c3 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -328,16 +328,10 @@ static bool radeon_fence_seq_signaled(struct radeon_device *rdev, */ bool radeon_fence_signaled(struct radeon_fence *fence) { - if (!fence) { - return true; - } - if (fence->seq == RADEON_FENCE_SIGNALED_SEQ) { + if (!fence) return true; - } - if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) { - fence->seq = RADEON_FENCE_SIGNALED_SEQ; + if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) return true; - } return false; } @@ -445,15 +439,11 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr) } seq[fence->ring] = fence->seq; - if (seq[fence->ring] == RADEON_FENCE_SIGNALED_SEQ) - return 0; - r = radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, MAX_SCHEDULE_TIMEOUT); if (r < 0) { return r; } - fence->seq = RADEON_FENCE_SIGNALED_SEQ; return 0; } @@ -487,10 +477,6 @@ int radeon_fence_wait_any(struct radeon_device *rdev, seq[i] = fences[i]->seq; ++num_rings; - - /* test if something was allready signaled */ - if (seq[i] == RADEON_FENCE_SIGNALED_SEQ) - return 0; } /* nothing to wait for ? */ -- GitLab From 3c0363891c0fa5d17b683b758bff0d81fa6a9775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 27 Aug 2014 15:22:01 +0200 Subject: [PATCH 0736/5088] drm/radeon: drop doing resets in a work item MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Blocking completely innocent processes with a GPU reset is a pretty bad idea. Just set needs_reset and let the next command submission or fence wait do the job. Signed-off-by: Christian König Reviewed-by: Maarten Lankhorst Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/cik.c | 6 ++++-- drivers/gpu/drm/radeon/radeon.h | 1 - drivers/gpu/drm/radeon/radeon_device.c | 7 ++++--- drivers/gpu/drm/radeon/radeon_irq_kms.c | 18 ------------------ 4 files changed, 8 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 79a5a5519bd6..1f598ab3b9a7 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -8246,8 +8246,10 @@ int cik_irq_process(struct radeon_device *rdev) } if (queue_hotplug) schedule_work(&rdev->hotplug_work); - if (queue_reset) - schedule_work(&rdev->reset_work); + if (queue_reset) { + rdev->needs_reset = true; + wake_up_all(&rdev->fence_queue); + } if (queue_thermal) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 896a84779650..c163b4f89149 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -2346,7 +2346,6 @@ struct radeon_device { struct radeon_mec mec; struct work_struct hotplug_work; struct work_struct audio_work; - struct work_struct reset_work; int num_crtc; /* number of crtcs */ struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */ bool has_uvd; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 9f666370b5ac..d30f1cc1aa12 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1673,9 +1673,6 @@ int radeon_gpu_reset(struct radeon_device *rdev) return 0; } - rdev->in_reset = true; - rdev->needs_reset = false; - radeon_save_bios_scratch_regs(rdev); /* block TTM */ resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); @@ -1738,6 +1735,10 @@ int radeon_gpu_reset(struct radeon_device *rdev) radeon_hpd_init(rdev); ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); + + rdev->in_reset = true; + rdev->needs_reset = false; + downgrade_write(&rdev->exclusive_lock); drm_helper_resume_force_mode(rdev->ddev); diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 16807afab362..f0bff4be67f1 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -87,23 +87,6 @@ static void radeon_hotplug_work_func(struct work_struct *work) drm_helper_hpd_irq_event(dev); } -/** - * radeon_irq_reset_work_func - execute gpu reset - * - * @work: work struct - * - * Execute scheduled gpu reset (cayman+). - * This function is called when the irq handler - * thinks we need a gpu reset. - */ -static void radeon_irq_reset_work_func(struct work_struct *work) -{ - struct radeon_device *rdev = container_of(work, struct radeon_device, - reset_work); - - radeon_gpu_reset(rdev); -} - /** * radeon_driver_irq_preinstall_kms - drm irq preinstall callback * @@ -284,7 +267,6 @@ int radeon_irq_kms_init(struct radeon_device *rdev) INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi); - INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func); rdev->irq.installed = true; r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq); -- GitLab From aa8e4f22ab7773352ba3895597189b8097f2c307 Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Wed, 27 Aug 2014 14:40:39 -0700 Subject: [PATCH 0737/5088] x86/iosf: Add Kconfig prompt for IOSF_MBI selection Fixes an error in having the iosf build as 'default m'. On X86 SoC's the iosf sideband is the only way to access information for some registers, as opposed to through MSR's on other Intel architectures. While selecting IOSF_MBI is preferred, it does mean carrying extra code on non-SoC architectures. This exports the selection to the user, allowing those driver writers to compile out iosf code if it's not being built. Signed-off-by: David E. Box Link: http://lkml.kernel.org/r/1409175640-32426-2-git-send-email-david.e.box@linux.intel.com Signed-off-by: H. Peter Anvin --- arch/x86/Kconfig | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5d0bf1aa9dcb..a99988f991ed 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2433,9 +2433,19 @@ config X86_DMA_REMAP depends on STA2X11 config IOSF_MBI - tristate - default m + tristate "Intel System On Chip IOSF Sideband support" depends on PCI + ---help--- + Enables sideband access to mailbox registers on SoC's. The sideband is + available on the following platforms. This list is not meant to be + exclusive. + - BayTrail + - Cherryview + - Braswell + - Quark + + You should say Y if you are running a kernel on one of these + platforms. config PMC_ATOM def_bool y -- GitLab From 8dc12f933c9d732c5bbfb233daf27377893b109c Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Wed, 27 Aug 2014 14:40:40 -0700 Subject: [PATCH 0738/5088] x86/iosf: Add debugfs support Allows access to the iosf sideband through debugfs. Signed-off-by: David E. Box Link: http://lkml.kernel.org/r/1409175640-32426-3-git-send-email-david.e.box@linux.intel.com Signed-off-by: H. Peter Anvin --- arch/x86/kernel/iosf_mbi.c | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/arch/x86/kernel/iosf_mbi.c b/arch/x86/kernel/iosf_mbi.c index 9030e83db6ee..0a2faa3892cb 100644 --- a/arch/x86/kernel/iosf_mbi.c +++ b/arch/x86/kernel/iosf_mbi.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include @@ -187,6 +189,75 @@ bool iosf_mbi_available(void) } EXPORT_SYMBOL(iosf_mbi_available); +/********************** debugfs begin ****************************/ +static u32 dbg_mdr; +static u32 dbg_mcr; +static u32 dbg_mcrx; + +static int mcr_get(void *data, u64 *val) +{ + *val = *(u32 *)data; + return 0; +} + +static int mcr_set(void *data, u64 val) +{ + u8 command = ((u32)val & 0xFF000000) >> 24, + port = ((u32)val & 0x00FF0000) >> 16, + offset = ((u32)val & 0x0000FF00) >> 8; + int err; + + *(u32 *)data = val; + + if (!capable(CAP_SYS_RAWIO)) + return -EACCES; + + if (command & 1u) + err = iosf_mbi_write(port, + command, + dbg_mcrx | offset, + dbg_mdr); + else + err = iosf_mbi_read(port, + command, + dbg_mcrx | offset, + &dbg_mdr); + + return err; +} +DEFINE_SIMPLE_ATTRIBUTE(iosf_mcr_fops, mcr_get, mcr_set , "%llx\n"); + +static struct dentry *iosf_dbg; +static void iosf_sideband_debug_init(void) +{ + struct dentry *d; + + iosf_dbg = debugfs_create_dir("iosf_sb", NULL); + if (IS_ERR_OR_NULL(iosf_dbg)) + return; + + /* mdr */ + d = debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr); + if (IS_ERR_OR_NULL(d)) + goto cleanup; + + /* mcrx */ + debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx); + if (IS_ERR_OR_NULL(d)) + goto cleanup; + + /* mcr - initiates mailbox tranaction */ + debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops); + if (IS_ERR_OR_NULL(d)) + goto cleanup; + + return; + +cleanup: + debugfs_remove_recursive(d); +} +/********************** debugfs end ****************************/ + static int iosf_mbi_probe(struct pci_dev *pdev, const struct pci_device_id *unused) { @@ -217,11 +288,14 @@ static struct pci_driver iosf_mbi_pci_driver = { static int __init iosf_mbi_init(void) { + iosf_sideband_debug_init(); return pci_register_driver(&iosf_mbi_pci_driver); } static void __exit iosf_mbi_exit(void) { + debugfs_remove_recursive(iosf_dbg); + pci_unregister_driver(&iosf_mbi_pci_driver); if (mbi_pdev) { pci_dev_put(mbi_pdev); -- GitLab From 3852752ca89ca00aa13f12a9b9450fd97ff437d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 21 Aug 2014 12:18:12 +0200 Subject: [PATCH 0739/5088] drm/radeon: allow UVD to use a second 256MB segment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This improves concurrent stream decoding. Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon.h | 3 ++- drivers/gpu/drm/radeon/radeon_object.c | 5 +++-- drivers/gpu/drm/radeon/radeon_uvd.c | 20 ++++++++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index a5ac95bf05ea..83a24614138a 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1642,7 +1642,8 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence); int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence); -void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo); +void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo, + uint32_t allowed_domains); void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp); int radeon_uvd_cs_parse(struct radeon_cs_parser *parser); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 0129c7efae3b..c97a42432e2b 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -491,6 +491,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev, bo = lobj->robj; if (!bo->pin_count) { u32 domain = lobj->prefered_domains; + u32 allowed = lobj->allowed_domains; u32 current_domain = radeon_mem_type_to_domain(bo->tbo.mem.mem_type); @@ -502,7 +503,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev, * into account. We don't want to disallow buffer moves * completely. */ - if ((lobj->allowed_domains & current_domain) != 0 && + if ((allowed & current_domain) != 0 && (domain & current_domain) == 0 && /* will be moved */ bytes_moved > bytes_moved_threshold) { /* don't move it */ @@ -512,7 +513,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev, retry: radeon_ttm_placement_from_domain(bo, domain); if (ring == R600_RING_TYPE_UVD_INDEX) - radeon_uvd_force_into_uvd_segment(bo); + radeon_uvd_force_into_uvd_segment(bo, allowed); initial_bytes_moved = atomic64_read(&rdev->num_bytes_moved); r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 464d80145dfe..1dedadd8f5df 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -254,7 +254,8 @@ int radeon_uvd_resume(struct radeon_device *rdev) return 0; } -void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo) +void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo, + uint32_t allowed_domains) { int i; @@ -262,6 +263,21 @@ void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo) rbo->placements[i].fpfn = 0 >> PAGE_SHIFT; rbo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; } + + /* If it must be in VRAM it must be in the first segment as well */ + if (allowed_domains == RADEON_GEM_DOMAIN_VRAM) + return; + + /* abort if we already have more than one placement */ + if (rbo->placement.num_placement > 1) + return; + + /* add another 256MB segment */ + rbo->placements[1] = rbo->placements[0]; + rbo->placements[1].fpfn += (256 * 1024 * 1024) >> PAGE_SHIFT; + rbo->placements[1].lpfn += (256 * 1024 * 1024) >> PAGE_SHIFT; + rbo->placement.num_placement++; + rbo->placement.num_busy_placement++; } void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp) @@ -652,7 +668,7 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev, return r; radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_VRAM); - radeon_uvd_force_into_uvd_segment(bo); + radeon_uvd_force_into_uvd_segment(bo, RADEON_GEM_DOMAIN_VRAM); r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); if (r) -- GitLab From feba9b0bcf492ba991d7fbfc211dd49ebbc95a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 22 Aug 2014 14:25:55 +0200 Subject: [PATCH 0740/5088] drm/radeon: preallocate mem for UVD create/destroy msg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit llocating memory for UVD create and destroy messages can fail, which is rather annoying when this happens in the middle of a GPU reset. Try to avoid this condition by preallocating a page for those dummy messages. Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_uvd.c | 101 +++++++--------------------- 1 file changed, 26 insertions(+), 75 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 1dedadd8f5df..5729e9bebd9d 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -138,7 +138,8 @@ int radeon_uvd_init(struct radeon_device *rdev) } bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) + - RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE; + RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE + + RADEON_GPU_PAGE_SIZE; r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, 0, NULL, &rdev->uvd.vcpu_bo); if (r) { @@ -647,38 +648,16 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p) } static int radeon_uvd_send_msg(struct radeon_device *rdev, - int ring, struct radeon_bo *bo, + int ring, uint64_t addr, struct radeon_fence **fence) { - struct ttm_validate_buffer tv; - struct ww_acquire_ctx ticket; - struct list_head head; struct radeon_ib ib; - uint64_t addr; int i, r; - memset(&tv, 0, sizeof(tv)); - tv.bo = &bo->tbo; - - INIT_LIST_HEAD(&head); - list_add(&tv.head, &head); - - r = ttm_eu_reserve_buffers(&ticket, &head); - if (r) - return r; - - radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_VRAM); - radeon_uvd_force_into_uvd_segment(bo, RADEON_GEM_DOMAIN_VRAM); - - r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); - if (r) - goto err; - r = radeon_ib_get(rdev, ring, &ib, NULL, 64); if (r) - goto err; + return r; - addr = radeon_bo_gpu_offset(bo); ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0); ib.ptr[1] = addr; ib.ptr[2] = PACKET0(UVD_GPCOM_VCPU_DATA1, 0); @@ -690,19 +669,11 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev, ib.length_dw = 16; r = radeon_ib_schedule(rdev, &ib, NULL, false); - if (r) - goto err; - ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence); if (fence) *fence = radeon_fence_ref(ib.fence); radeon_ib_free(rdev, &ib); - radeon_bo_unref(&bo); - return 0; - -err: - ttm_eu_backoff_reservation(&ticket, &head); return r; } @@ -712,27 +683,18 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev, int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence) { - struct radeon_bo *bo; - uint32_t *msg; - int r, i; + /* we use the last page of the vcpu bo for the UVD message */ + uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) - + RADEON_GPU_PAGE_SIZE; - r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, 0, NULL, &bo); - if (r) - return r; + uint32_t *msg = rdev->uvd.cpu_addr + offs; + uint64_t addr = rdev->uvd.gpu_addr + offs; - r = radeon_bo_reserve(bo, false); - if (r) { - radeon_bo_unref(&bo); - return r; - } + int r, i; - r = radeon_bo_kmap(bo, (void **)&msg); - if (r) { - radeon_bo_unreserve(bo); - radeon_bo_unref(&bo); + r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true); + if (r) return r; - } /* stitch together an UVD create msg */ msg[0] = cpu_to_le32(0x00000de4); @@ -749,36 +711,26 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, for (i = 11; i < 1024; ++i) msg[i] = cpu_to_le32(0x0); - radeon_bo_kunmap(bo); - radeon_bo_unreserve(bo); - - return radeon_uvd_send_msg(rdev, ring, bo, fence); + r = radeon_uvd_send_msg(rdev, ring, addr, fence); + radeon_bo_unreserve(rdev->uvd.vcpu_bo); + return r; } int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence) { - struct radeon_bo *bo; - uint32_t *msg; - int r, i; + /* we use the last page of the vcpu bo for the UVD message */ + uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) - + RADEON_GPU_PAGE_SIZE; - r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_VRAM, 0, NULL, &bo); - if (r) - return r; + uint32_t *msg = rdev->uvd.cpu_addr + offs; + uint64_t addr = rdev->uvd.gpu_addr + offs; - r = radeon_bo_reserve(bo, false); - if (r) { - radeon_bo_unref(&bo); - return r; - } + int r, i; - r = radeon_bo_kmap(bo, (void **)&msg); - if (r) { - radeon_bo_unreserve(bo); - radeon_bo_unref(&bo); + r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true); + if (r) return r; - } /* stitch together an UVD destroy msg */ msg[0] = cpu_to_le32(0x00000de4); @@ -788,10 +740,9 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, for (i = 4; i < 1024; ++i) msg[i] = cpu_to_le32(0x0); - radeon_bo_kunmap(bo); - radeon_bo_unreserve(bo); - - return radeon_uvd_send_msg(rdev, ring, bo, fence); + r = radeon_uvd_send_msg(rdev, ring, addr, fence); + radeon_bo_unreserve(rdev->uvd.vcpu_bo); + return r; } /** -- GitLab From 58d06e989e1321b43c1e42bdf3846113e9e16ecd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 20 Aug 2014 15:18:44 +0200 Subject: [PATCH 0741/5088] dmaengine: Update documentation for inline wrapper Commit 16052827d98fbc13c31ebad560af4bd53e2b4dd5 ("dmaengine/dma_slave: introduce inline wrappers") introduced some wrappers, but there is still a reference to the old function. Update the documentation to use the wrapper, and add a missing "()" to a function name. Signed-off-by: Geert Uytterhoeven Signed-off-by: Vinod Koul --- Documentation/dmaengine.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/dmaengine.txt b/Documentation/dmaengine.txt index 573e28ce9751..11fb87ff6cd0 100644 --- a/Documentation/dmaengine.txt +++ b/Documentation/dmaengine.txt @@ -98,7 +98,7 @@ The slave DMA usage consists of following steps: unsigned long flags); The peripheral driver is expected to have mapped the scatterlist for - the DMA operation prior to calling device_prep_slave_sg, and must + the DMA operation prior to calling dmaengine_prep_slave_sg(), and must keep the scatterlist mapped until the DMA operation has completed. The scatterlist must be mapped using the DMA struct device. If a mapping needs to be synchronized later, dma_sync_*_for_*() must be @@ -195,5 +195,5 @@ Further APIs: Note: Not all DMA engine drivers can return reliable information for a running DMA channel. It is recommended that DMA engine users - pause or stop (via dmaengine_terminate_all) the channel before + pause or stop (via dmaengine_terminate_all()) the channel before using this API. -- GitLab From b19f40b8bf87bfc32b91260a90a7fa2cdebcd9bb Mon Sep 17 00:00:00 2001 From: Ryo Kataoka Date: Wed, 20 Aug 2014 17:53:03 -0700 Subject: [PATCH 0742/5088] dma: rcar-audmapp: Fix for no corresponding slave ID In case of no corresponding slave ID, the audmapp_set_slave() returns -ENXIO same as sh_dmae_set_slave() of shdmac.c. DMAEngine might return wrong channel without this patch Signed-off-by: Ryo Kataoka Signed-off-by: Jun Watanabe , Signed-off-by: Kuninori Morimoto Signed-off-by: Vinod Koul --- drivers/dma/sh/rcar-audmapp.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c index dabbf0aba2e9..80fd2aeb4870 100644 --- a/drivers/dma/sh/rcar-audmapp.c +++ b/drivers/dma/sh/rcar-audmapp.c @@ -117,7 +117,7 @@ static void audmapp_start_xfer(struct shdma_chan *schan, audmapp_write(auchan, chcr, PDMACHCR); } -static void audmapp_get_config(struct audmapp_chan *auchan, int slave_id, +static int audmapp_get_config(struct audmapp_chan *auchan, int slave_id, u32 *chcr, dma_addr_t *dst) { struct audmapp_device *audev = to_dev(auchan); @@ -131,20 +131,22 @@ static void audmapp_get_config(struct audmapp_chan *auchan, int slave_id, if (!pdata) { /* DT */ *chcr = ((u32)slave_id) << 16; auchan->shdma_chan.slave_id = (slave_id) >> 8; - return; + return 0; } /* non-DT */ if (slave_id >= AUDMAPP_SLAVE_NUMBER) - return; + return -ENXIO; for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++) if (cfg->slave_id == slave_id) { *chcr = cfg->chcr; *dst = cfg->dst; - break; + return 0; } + + return -ENXIO; } static int audmapp_set_slave(struct shdma_chan *schan, int slave_id, @@ -153,8 +155,11 @@ static int audmapp_set_slave(struct shdma_chan *schan, int slave_id, struct audmapp_chan *auchan = to_chan(schan); u32 chcr; dma_addr_t dst; + int ret; - audmapp_get_config(auchan, slave_id, &chcr, &dst); + ret = audmapp_get_config(auchan, slave_id, &chcr, &dst); + if (ret < 0) + return ret; if (try) return 0; -- GitLab From e34b731faa7d12d3681187968ef899747e4feb55 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Aug 2014 11:55:53 +0100 Subject: [PATCH 0743/5088] dma: imx-sdma: Remove spurious __init annotation on sdma_probe() We can't annotate probe functions as __init since binding can occur at any time, not just during kernel init. Signed-off-by: Mark Brown Acked-by: Shawn Guo Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index c615e88c118a..52ce1d21154c 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1448,7 +1448,7 @@ static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec, return dma_request_channel(mask, sdma_filter_fn, &data); } -static int __init sdma_probe(struct platform_device *pdev) +static int sdma_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(sdma_dt_ids, &pdev->dev); -- GitLab From 4bb93349d9d001f565aafe2a1890cbb6e4476b58 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Tue, 29 Jul 2014 09:24:43 +0200 Subject: [PATCH 0744/5088] gpio: pca953x: Drop deprecated DT bindings Drop deprecated DT bindings and use automaticly assigned gpio and irq bases. Signed-off-by: Markus Pargmann Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 54 +++---------------------------------- 1 file changed, 3 insertions(+), 51 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index f9961eea2120..e2da64abbccd 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -520,7 +520,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, struct i2c_client *client = chip->client; int ret, i, offset = 0; - if (irq_base != -1 + if (client->irq && irq_base != -1 && (id->driver_data & PCA_INT)) { switch (chip->chip_type) { @@ -586,50 +586,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, } #endif -/* - * Handlers for alternative sources of platform_data - */ -#ifdef CONFIG_OF_GPIO -/* - * Translate OpenFirmware node properties into platform_data - * WARNING: This is DEPRECATED and will be removed eventually! - */ -static void -pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) -{ - struct device_node *node; - const __be32 *val; - int size; - - *gpio_base = -1; - - node = client->dev.of_node; - if (node == NULL) - return; - - val = of_get_property(node, "linux,gpio-base", &size); - WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__); - if (val) { - if (size != sizeof(*val)) - dev_warn(&client->dev, "%s: wrong linux,gpio-base\n", - node->full_name); - else - *gpio_base = be32_to_cpup(val); - } - - val = of_get_property(node, "polarity", NULL); - WARN(val, "%s: device-tree property 'polarity' is deprecated!", __func__); - if (val) - *invert = *val; -} -#else -static void -pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) -{ - *gpio_base = -1; -} -#endif - static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) { int ret; @@ -704,12 +660,8 @@ static int pca953x_probe(struct i2c_client *client, invert = pdata->invert; chip->names = pdata->names; } else { - pca953x_get_alt_pdata(client, &chip->gpio_start, &invert); -#ifdef CONFIG_OF_GPIO - /* If I2C node has no interrupts property, disable GPIO interrupts */ - if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL) - irq_base = -1; -#endif + chip->gpio_start = -1; + irq_base = 0; } chip->client = client; -- GitLab From e8126753a9a5896ed50c9d9bf66fa46f0f1982a6 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Tue, 29 Jul 2014 09:24:44 +0200 Subject: [PATCH 0745/5088] gpio: pca953x: Add DT binding documentation Add a devicetree binding documentation for the pca953x driver. Signed-off-by: Markus Pargmann Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-pca953x.txt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-pca953x.txt diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt new file mode 100644 index 000000000000..b9a42f294dd0 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt @@ -0,0 +1,39 @@ +* NXP PCA953x I2C GPIO multiplexer + +Required properties: + - compatible: Has to contain one of the following: + nxp,pca9505 + nxp,pca9534 + nxp,pca9535 + nxp,pca9536 + nxp,pca9537 + nxp,pca9538 + nxp,pca9539 + nxp,pca9554 + nxp,pca9555 + nxp,pca9556 + nxp,pca9557 + nxp,pca9574 + nxp,pca9575 + nxp,pca9698 + maxim,max7310 + maxim,max7312 + maxim,max7313 + maxim,max7315 + ti,pca6107 + ti,tca6408 + ti,tca6416 + ti,tca6424 + exar,xra1202 + +Example: + + + gpio@20 { + compatible = "nxp,pca9505"; + reg = <0x20>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pca9505>; + interrupt-parent = <&gpio3>; + interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + }; -- GitLab From 29cbf4589fc0dabef4dfc95dd9589c366ad2ec46 Mon Sep 17 00:00:00 2001 From: Feng Kan Date: Thu, 31 Jul 2014 12:03:25 -0700 Subject: [PATCH 0746/5088] gpio: Add APM X-Gene SoC GPIO controller support Add APM X-Gene SoC gpio controller driver. Signed-off-by: Feng Kan Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 9 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-xgene.c | 250 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 drivers/gpio/gpio-xgene.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9de1515e5808..1fe93eb61927 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -334,6 +334,15 @@ config GPIO_TZ1090_PDC help Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs. +config GPIO_XGENE + bool "APM X-Gene GPIO controller support" + depends on ARM64 && OF_GPIO + help + This driver is to support the GPIO block within the APM X-Gene SoC + platform's generic flash controller. The GPIO pins are muxed with + the generic flash controller's address and data pins. Say yes + here to enable the GFC GPIO functionality. + config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 5d024e396622..e5d346cf3b6e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o +obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c new file mode 100644 index 000000000000..e25ba14fbb64 --- /dev/null +++ b/drivers/gpio/gpio-xgene.c @@ -0,0 +1,250 @@ +/* + * AppliedMicro X-Gene SoC GPIO Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Feng Kan . + * + * 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 +#include +#include +#include +#include +#include +#include + +#define GPIO_SET_DR_OFFSET 0x0C +#define GPIO_DATA_OFFSET 0x14 +#define GPIO_BANK_STRIDE 0x0C + +#define XGENE_GPIOS_PER_BANK 16 +#define XGENE_MAX_GPIO_BANKS 3 +#define XGENE_MAX_GPIOS (XGENE_GPIOS_PER_BANK * XGENE_MAX_GPIO_BANKS) + +#define GPIO_BIT_OFFSET(x) (x % XGENE_GPIOS_PER_BANK) +#define GPIO_BANK_OFFSET(x) ((x / XGENE_GPIOS_PER_BANK) * GPIO_BANK_STRIDE) + +struct xgene_gpio; + +struct xgene_gpio { + struct gpio_chip chip; + void __iomem *base; + spinlock_t lock; +#ifdef CONFIG_PM + u32 set_dr_val[XGENE_MAX_GPIO_BANKS]; +#endif +}; + +static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct xgene_gpio, chip); +} + +static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long bank_offset; + u32 bit_offset; + + bank_offset = GPIO_DATA_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset); + return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset)); +} + +static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long bank_offset; + u32 setval, bit_offset; + + bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset) + XGENE_GPIOS_PER_BANK; + + setval = ioread32(chip->base + bank_offset); + if (val) + setval |= BIT(bit_offset); + else + setval &= ~BIT(bit_offset); + iowrite32(setval, chip->base + bank_offset); +} + +static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long flags; + + spin_lock_irqsave(&chip->lock, flags); + __xgene_gpio_set(gc, offset, val); + spin_unlock_irqrestore(&chip->lock, flags); +} + +static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long flags, bank_offset; + u32 dirval, bit_offset; + + bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset); + + spin_lock_irqsave(&chip->lock, flags); + + dirval = ioread32(chip->base + bank_offset); + dirval |= BIT(bit_offset); + iowrite32(dirval, chip->base + bank_offset); + + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int xgene_gpio_dir_out(struct gpio_chip *gc, + unsigned int offset, int val) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long flags, bank_offset; + u32 dirval, bit_offset; + + bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset); + + spin_lock_irqsave(&chip->lock, flags); + + dirval = ioread32(chip->base + bank_offset); + dirval &= ~BIT(bit_offset); + iowrite32(dirval, chip->base + bank_offset); + __xgene_gpio_set(gc, offset, val); + + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +#ifdef CONFIG_PM +static int xgene_gpio_suspend(struct device *dev) +{ + struct xgene_gpio *gpio = dev_get_drvdata(dev); + unsigned long bank_offset; + unsigned int bank; + + for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) { + bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE; + gpio->set_dr_val[bank] = ioread32(gpio->base + bank_offset); + } + return 0; +} + +static int xgene_gpio_resume(struct device *dev) +{ + struct xgene_gpio *gpio = dev_get_drvdata(dev); + unsigned long bank_offset; + unsigned int bank; + + for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) { + bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE; + iowrite32(gpio->set_dr_val[bank], gpio->base + bank_offset); + } + return 0; +} + +static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume); +#define XGENE_GPIO_PM_OPS (&xgene_gpio_pm) +#else +#define XGENE_GPIO_PM_OPS NULL +#endif + +static int xgene_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + struct xgene_gpio *gpio; + int err = 0; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + err = -ENOMEM; + goto err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gpio->base = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (IS_ERR(gpio->base)) { + err = PTR_ERR(gpio->base); + goto err; + } + + gpio->chip.ngpio = XGENE_MAX_GPIOS; + + gpio->chip.dev = &pdev->dev; + gpio->chip.direction_input = xgene_gpio_dir_in; + gpio->chip.direction_output = xgene_gpio_dir_out; + gpio->chip.get = xgene_gpio_get; + gpio->chip.set = xgene_gpio_set; + gpio->chip.label = dev_name(&pdev->dev); + gpio->chip.base = -1; + + platform_set_drvdata(pdev, gpio); + + err = gpiochip_add(&gpio->chip); + if (err) { + dev_err(&pdev->dev, + "failed to register gpiochip.\n"); + goto err; + } + + dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n"); + return 0; +err: + dev_err(&pdev->dev, "X-Gene GPIO driver registration failed.\n"); + return err; +} + +static int xgene_gpio_remove(struct platform_device *pdev) +{ + struct xgene_gpio *gpio = platform_get_drvdata(pdev); + int ret = 0; + + ret = gpiochip_remove(&gpio->chip); + if (ret) + dev_err(&pdev->dev, "unable to remove gpio_chip.\n"); + return ret; +} + +#ifdef CONFIG_OF +static const struct of_device_id xgene_gpio_of_match[] = { + { .compatible = "apm,xgene-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_gpio_of_match); +#endif + +static struct platform_driver xgene_gpio_driver = { + .driver = { + .name = "xgene-gpio", + .owner = THIS_MODULE, + .of_match_table = xgene_gpio_of_match, + .pm = XGENE_GPIO_PM_OPS, + }, + .probe = xgene_gpio_probe, + .remove = xgene_gpio_remove, +}; + +module_platform_driver(xgene_gpio_driver); + +MODULE_AUTHOR("Feng Kan "); +MODULE_DESCRIPTION("APM X-Gene GPIO driver"); +MODULE_LICENSE("GPL"); -- GitLab From 1b5bda21b05ef1b3c5462d4f066fda7c68240dda Mon Sep 17 00:00:00 2001 From: Feng Kan Date: Thu, 31 Jul 2014 12:03:26 -0700 Subject: [PATCH 0747/5088] Documentation: gpio: Add APM X-Gene SoC GPIO controller DTS binding Documentation for APM X-Gene SoC GPIO controller DTS binding. Signed-off-by: Feng Kan Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-xgene.txt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-xgene.txt diff --git a/Documentation/devicetree/bindings/gpio/gpio-xgene.txt b/Documentation/devicetree/bindings/gpio/gpio-xgene.txt new file mode 100644 index 000000000000..86dbb05e7758 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-xgene.txt @@ -0,0 +1,22 @@ +APM X-Gene SoC GPIO controller bindings + +This is a gpio controller that is part of the flash controller. +This gpio controller controls a total of 48 gpios. + +Required properties: +- compatible: "apm,xgene-gpio" for X-Gene GPIO controller +- reg: Physical base address and size of the controller's registers +- #gpio-cells: Should be two. + - first cell is the pin number + - second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- gpio-controller: Marks the device node as a GPIO controller. + +Example: + gpio0: gpio0@1701c000 { + compatible = "apm,xgene-gpio"; + reg = <0x0 0x1701c000 0x0 0x40>; + gpio-controller; + #gpio-cells = <2>; + }; -- GitLab From 4ba2968420fa9d0604b6a6a5c61bfa8d0fa84ae0 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Tue, 26 Aug 2014 19:12:21 -0500 Subject: [PATCH 0748/5088] percpu: Resolve ambiguities in __get_cpu_var/cpumask_var_t __get_cpu_var can paper over differences in the definitions of cpumask_var_t and either use the address of the cpumask variable directly or perform a fetch of the address of the struct cpumask allocated elsewhere. This is important particularly when using per cpu cpumask_var_t declarations because in one case we have an offset into a per cpu area to handle and in the other case we need to fetch a pointer from the offset. This patch introduces a new macro this_cpu_cpumask_var_ptr() that is defined where cpumask_var_t is defined and performs the proper actions. All use cases where __get_cpu_var is used with cpumask_var_t are converted to the use of this_cpu_cpumask_var_ptr(). Signed-off-by: Christoph Lameter Signed-off-by: Tejun Heo --- arch/x86/include/asm/perf_event_p4.h | 2 +- arch/x86/kernel/apic/x2apic_cluster.c | 3 +-- arch/x86/oprofile/op_model_p4.c | 2 +- include/linux/cpumask.h | 11 +++++++++++ kernel/sched/deadline.c | 2 +- kernel/sched/fair.c | 2 +- kernel/sched/rt.c | 2 +- 7 files changed, 17 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/perf_event_p4.h b/arch/x86/include/asm/perf_event_p4.h index 85e13ccf15c4..d725382c2ae0 100644 --- a/arch/x86/include/asm/perf_event_p4.h +++ b/arch/x86/include/asm/perf_event_p4.h @@ -189,7 +189,7 @@ static inline int p4_ht_thread(int cpu) { #ifdef CONFIG_SMP if (smp_num_siblings == 2) - return cpu != cpumask_first(__get_cpu_var(cpu_sibling_map)); + return cpu != cpumask_first(this_cpu_cpumask_var_ptr(cpu_sibling_map)); #endif return 0; } diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index 6ce600f9bc78..1f5d5f2ffae6 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -42,8 +42,7 @@ __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest) * We are to modify mask, so we need an own copy * and be sure it's manipulated with irq off. */ - ipi_mask_ptr = __raw_get_cpu_var(ipi_mask); - cpumask_copy(ipi_mask_ptr, mask); + ipi_mask_ptr = this_cpu_cpumask_var_ptr(ipi_mask); /* * The idea is to send one IPI per cluster. diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c index 98ab13058f89..ad1d91f475ab 100644 --- a/arch/x86/oprofile/op_model_p4.c +++ b/arch/x86/oprofile/op_model_p4.c @@ -372,7 +372,7 @@ static unsigned int get_stagger(void) { #ifdef CONFIG_SMP int cpu = smp_processor_id(); - return cpu != cpumask_first(__get_cpu_var(cpu_sibling_map)); + return cpu != cpumask_first(this_cpu_cpumask_var_ptr(cpu_sibling_map)); #endif return 0; } diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 2997af6d2ccd..0a9a6da21e74 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -666,10 +666,19 @@ static inline size_t cpumask_size(void) * * This code makes NR_CPUS length memcopy and brings to a memory corruption. * cpumask_copy() provide safe copy functionality. + * + * Note that there is another evil here: If you define a cpumask_var_t + * as a percpu variable then the way to obtain the address of the cpumask + * structure differently influences what this_cpu_* operation needs to be + * used. Please use this_cpu_cpumask_var_t in those cases. The direct use + * of this_cpu_ptr() or this_cpu_read() will lead to failures when the + * other type of cpumask_var_t implementation is configured. */ #ifdef CONFIG_CPUMASK_OFFSTACK typedef struct cpumask *cpumask_var_t; +#define this_cpu_cpumask_var_ptr(x) this_cpu_read(x) + bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node); bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags); bool zalloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node); @@ -681,6 +690,8 @@ void free_bootmem_cpumask_var(cpumask_var_t mask); #else typedef struct cpumask cpumask_var_t[1]; +#define this_cpu_cpumask_var_ptr(x) this_cpu_ptr(x) + static inline bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags) { return true; diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 255ce138b652..4a608cfaecbd 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -1158,7 +1158,7 @@ static DEFINE_PER_CPU(cpumask_var_t, local_cpu_mask_dl); static int find_later_rq(struct task_struct *task) { struct sched_domain *sd; - struct cpumask *later_mask = __get_cpu_var(local_cpu_mask_dl); + struct cpumask *later_mask = this_cpu_cpumask_var_ptr(local_cpu_mask_dl); int this_cpu = smp_processor_id(); int best_cpu, cpu = task_cpu(task); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index bfa3c86d0d68..197d659c144c 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6539,7 +6539,7 @@ static int load_balance(int this_cpu, struct rq *this_rq, struct sched_group *group; struct rq *busiest; unsigned long flags; - struct cpumask *cpus = __get_cpu_var(load_balance_mask); + struct cpumask *cpus = this_cpu_cpumask_var_ptr(load_balance_mask); struct lb_env env = { .sd = sd, diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 5f6edca4fafd..a4c50fce9b90 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1526,7 +1526,7 @@ static DEFINE_PER_CPU(cpumask_var_t, local_cpu_mask); static int find_lowest_rq(struct task_struct *task) { struct sched_domain *sd; - struct cpumask *lowest_mask = __get_cpu_var(local_cpu_mask); + struct cpumask *lowest_mask = this_cpu_cpumask_var_ptr(local_cpu_mask); int this_cpu = smp_processor_id(); int cpu = task_cpu(task); -- GitLab From 6728f2b109392484d38ac9e365496ac5fa1071f1 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Wed, 13 Aug 2014 13:38:38 +0100 Subject: [PATCH 0749/5088] backlight: Remove .owner field for drivers using module_platform_driver This patch removes the superflous .owner field for drivers which use the module_platform_driver or platform_driver_register api, as this is overriden in __platform_driver_register. Signed-off-by: Peter Griffin Signed-off-by: Lee Jones --- drivers/video/backlight/88pm860x_bl.c | 1 - drivers/video/backlight/aat2870_bl.c | 1 - drivers/video/backlight/adp5520_bl.c | 1 - drivers/video/backlight/as3711_bl.c | 1 - drivers/video/backlight/da903x_bl.c | 1 - drivers/video/backlight/da9052_bl.c | 1 - drivers/video/backlight/ep93xx_bl.c | 1 - drivers/video/backlight/gpio_backlight.c | 1 - drivers/video/backlight/lm3533_bl.c | 1 - drivers/video/backlight/lp8788_bl.c | 1 - drivers/video/backlight/max8925_bl.c | 1 - drivers/video/backlight/ot200_bl.c | 1 - drivers/video/backlight/pandora_bl.c | 1 - drivers/video/backlight/platform_lcd.c | 1 - drivers/video/backlight/pwm_bl.c | 1 - drivers/video/backlight/tps65217_bl.c | 1 - drivers/video/backlight/wm831x_bl.c | 1 - 17 files changed, 17 deletions(-) diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 7db5234462d0..6214fc62ad9c 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -265,7 +265,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev) static struct platform_driver pm860x_backlight_driver = { .driver = { .name = "88pm860x-backlight", - .owner = THIS_MODULE, }, .probe = pm860x_backlight_probe, }; diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index 86234c31d79c..50774e657700 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -211,7 +211,6 @@ static int aat2870_bl_remove(struct platform_device *pdev) static struct platform_driver aat2870_bl_driver = { .driver = { .name = "aat2870-backlight", - .owner = THIS_MODULE, }, .probe = aat2870_bl_probe, .remove = aat2870_bl_remove, diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index f37097a261a2..b56cb3f77174 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -374,7 +374,6 @@ static SIMPLE_DEV_PM_OPS(adp5520_bl_pm_ops, adp5520_bl_suspend, static struct platform_driver adp5520_bl_driver = { .driver = { .name = "adp5520-backlight", - .owner = THIS_MODULE, .pm = &adp5520_bl_pm_ops, }, .probe = adp5520_bl_probe, diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c index bb1fc45b7549..734a9158946b 100644 --- a/drivers/video/backlight/as3711_bl.c +++ b/drivers/video/backlight/as3711_bl.c @@ -467,7 +467,6 @@ static int as3711_backlight_probe(struct platform_device *pdev) static struct platform_driver as3711_backlight_driver = { .driver = { .name = "as3711-backlight", - .owner = THIS_MODULE, }, .probe = as3711_backlight_probe, }; diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index 12c5d840c590..f793738f06fb 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -162,7 +162,6 @@ static int da903x_backlight_probe(struct platform_device *pdev) static struct platform_driver da903x_backlight_driver = { .driver = { .name = "da903x-backlight", - .owner = THIS_MODULE, }, .probe = da903x_backlight_probe, }; diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c index 20d55becaa74..d4bd74bd5070 100644 --- a/drivers/video/backlight/da9052_bl.c +++ b/drivers/video/backlight/da9052_bl.c @@ -173,7 +173,6 @@ static struct platform_driver da9052_wled_driver = { .id_table = da9052_wled_ids, .driver = { .name = "da9052-wled", - .owner = THIS_MODULE, }, }; diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c index 0d1f633c6480..0067931821c6 100644 --- a/drivers/video/backlight/ep93xx_bl.c +++ b/drivers/video/backlight/ep93xx_bl.c @@ -128,7 +128,6 @@ static SIMPLE_DEV_PM_OPS(ep93xxbl_pm_ops, ep93xxbl_suspend, ep93xxbl_resume); static struct platform_driver ep93xxbl_driver = { .driver = { .name = "ep93xx-bl", - .owner = THIS_MODULE, .pm = &ep93xxbl_pm_ops, }, .probe = ep93xxbl_probe, diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c index aaead04a2d54..439feb2389a8 100644 --- a/drivers/video/backlight/gpio_backlight.c +++ b/drivers/video/backlight/gpio_backlight.c @@ -151,7 +151,6 @@ static struct of_device_id gpio_backlight_of_match[] = { static struct platform_driver gpio_backlight_driver = { .driver = { .name = "gpio-backlight", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(gpio_backlight_of_match), }, .probe = gpio_backlight_probe, diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c index cff1fbe89a1b..0e2337f367b6 100644 --- a/drivers/video/backlight/lm3533_bl.c +++ b/drivers/video/backlight/lm3533_bl.c @@ -397,7 +397,6 @@ static void lm3533_bl_shutdown(struct platform_device *pdev) static struct platform_driver lm3533_bl_driver = { .driver = { .name = "lm3533-backlight", - .owner = THIS_MODULE, .pm = &lm3533_bl_pm_ops, }, .probe = lm3533_bl_probe, diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c index d6c4f6a2d43e..e418d5b1aa55 100644 --- a/drivers/video/backlight/lp8788_bl.c +++ b/drivers/video/backlight/lp8788_bl.c @@ -315,7 +315,6 @@ static struct platform_driver lp8788_bl_driver = { .remove = lp8788_backlight_remove, .driver = { .name = LP8788_DEV_BACKLIGHT, - .owner = THIS_MODULE, }, }; module_platform_driver(lp8788_bl_driver); diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 66fa08c920d2..7b738d60ecc2 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -197,7 +197,6 @@ static int max8925_backlight_probe(struct platform_device *pdev) static struct platform_driver max8925_backlight_driver = { .driver = { .name = "max8925-backlight", - .owner = THIS_MODULE, }, .probe = max8925_backlight_probe, }; diff --git a/drivers/video/backlight/ot200_bl.c b/drivers/video/backlight/ot200_bl.c index f5a5202dd79d..3acdb9f646ed 100644 --- a/drivers/video/backlight/ot200_bl.c +++ b/drivers/video/backlight/ot200_bl.c @@ -152,7 +152,6 @@ static int ot200_backlight_remove(struct platform_device *pdev) static struct platform_driver ot200_backlight_driver = { .driver = { .name = "ot200-backlight", - .owner = THIS_MODULE, }, .probe = ot200_backlight_probe, .remove = ot200_backlight_remove, diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c index 2e3f82063c03..5d8bb8b20183 100644 --- a/drivers/video/backlight/pandora_bl.c +++ b/drivers/video/backlight/pandora_bl.c @@ -142,7 +142,6 @@ static int pandora_backlight_probe(struct platform_device *pdev) static struct platform_driver pandora_backlight_driver = { .driver = { .name = "pandora-backlight", - .owner = THIS_MODULE, }, .probe = pandora_backlight_probe, }; diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index c3d2e209fc8f..872a3bf21faf 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -148,7 +148,6 @@ MODULE_DEVICE_TABLE(of, platform_lcd_of_match); static struct platform_driver platform_lcd_driver = { .driver = { .name = "platform-lcd", - .owner = THIS_MODULE, .pm = &platform_lcd_pm_ops, .of_match_table = of_match_ptr(platform_lcd_of_match), }, diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index d7a3d13e72ec..20963ed5077d 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -389,7 +389,6 @@ static const struct dev_pm_ops pwm_backlight_pm_ops = { static struct platform_driver pwm_backlight_driver = { .driver = { .name = "pwm-backlight", - .owner = THIS_MODULE, .pm = &pwm_backlight_pm_ops, .of_match_table = of_match_ptr(pwm_backlight_of_match), }, diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index 2e04d93aa0ef..61d72bffd402 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -323,7 +323,6 @@ static int tps65217_bl_probe(struct platform_device *pdev) static struct platform_driver tps65217_bl_driver = { .probe = tps65217_bl_probe, .driver = { - .owner = THIS_MODULE, .name = "tps65217-bl", }, }; diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 8b9455e93069..6f596161916d 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -217,7 +217,6 @@ static int wm831x_backlight_probe(struct platform_device *pdev) static struct platform_driver wm831x_backlight_driver = { .driver = { .name = "wm831x-backlight", - .owner = THIS_MODULE, }, .probe = wm831x_backlight_probe, }; -- GitLab From 964a1c4e0e22cf2da7c35e7d57e61fcd7ba8ee21 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 27 Aug 2014 16:45:00 -0300 Subject: [PATCH 0750/5088] backlight: generic_bl: Remove unused function genericbl_limit_intensity() is exported, but it is never called anywhere else. Fix the following sparse warning: drivers/video/backlight/generic_bl.c:59:6: warning: symbol 'genericbl_limit_intensity' was not declared. Should it be static? Signed-off-by: Fabio Estevam Signed-off-by: Lee Jones --- drivers/video/backlight/generic_bl.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c index 5d8d65200db7..67dfb939a514 100644 --- a/drivers/video/backlight/generic_bl.c +++ b/drivers/video/backlight/generic_bl.c @@ -52,24 +52,6 @@ static int genericbl_get_intensity(struct backlight_device *bd) return genericbl_intensity; } -/* - * Called when the battery is low to limit the backlight intensity. - * If limit==0 clear any limit, otherwise limit the intensity - */ -void genericbl_limit_intensity(int limit) -{ - struct backlight_device *bd = generic_backlight_device; - - mutex_lock(&bd->ops_lock); - if (limit) - bd->props.state |= GENERICBL_BATTLOW; - else - bd->props.state &= ~GENERICBL_BATTLOW; - backlight_update_status(generic_backlight_device); - mutex_unlock(&bd->ops_lock); -} -EXPORT_SYMBOL(genericbl_limit_intensity); - static const struct backlight_ops genericbl_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = genericbl_get_intensity, -- GitLab From 77c545398e33a0263a68142fcfbd4b11b0f06294 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 28 Aug 2014 14:48:24 +0200 Subject: [PATCH 0751/5088] ASoC: Allow SND_SOC_WM8978 to be selected manually When using a DT-based multi-platform kernel, there's not always Kconfig logic that selects the right codec driver. Allow the user to manually select WM8978. This is needed for Armadillo 800 EVA using a generic r8a7740 multi-platform kernel. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..9c400a277592 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -712,7 +712,8 @@ config SND_SOC_WM8974 tristate config SND_SOC_WM8978 - tristate + tristate "Wolfson Microelectronics WM8978 codec" + depends on I2C config SND_SOC_WM8983 tristate -- GitLab From 7b0d0b40cd78cadb525df760ee4cac151533c2b5 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Mon, 4 Aug 2014 13:36:49 -0400 Subject: [PATCH 0752/5088] selinux: Permit bounded transitions under NO_NEW_PRIVS or NOSUID. If the callee SID is bounded by the caller SID, then allowing the transition to occur poses no risk of privilege escalation and we can therefore safely allow the transition to occur. Add this exemption for both the case where a transition was explicitly requested by the application and the case where an automatic transition is defined in policy. Signed-off-by: Stephen Smalley Reviewed-by: Andy Lutomirski Signed-off-by: Paul Moore --- security/selinux/hooks.c | 59 ++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b0e940497e23..6c90d491fab4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2097,6 +2097,41 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) /* binprm security operations */ +static int check_nnp_nosuid(const struct linux_binprm *bprm, + const struct task_security_struct *old_tsec, + const struct task_security_struct *new_tsec) +{ + int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS); + int nosuid = (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID); + int rc; + + if (!nnp && !nosuid) + return 0; /* neither NNP nor nosuid */ + + if (new_tsec->sid == old_tsec->sid) + return 0; /* No change in credentials */ + + /* + * The only transitions we permit under NNP or nosuid + * are transitions to bounded SIDs, i.e. SIDs that are + * guaranteed to only be allowed a subset of the permissions + * of the current SID. + */ + rc = security_bounded_transition(old_tsec->sid, new_tsec->sid); + if (rc) { + /* + * On failure, preserve the errno values for NNP vs nosuid. + * NNP: Operation not permitted for caller. + * nosuid: Permission denied to file. + */ + if (nnp) + return -EPERM; + else + return -EACCES; + } + return 0; +} + static int selinux_bprm_set_creds(struct linux_binprm *bprm) { const struct task_security_struct *old_tsec; @@ -2133,14 +2168,10 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) /* Reset exec SID on execve. */ new_tsec->exec_sid = 0; - /* - * Minimize confusion: if no_new_privs or nosuid and a - * transition is explicitly requested, then fail the exec. - */ - if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) - return -EPERM; - if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) - return -EACCES; + /* Fail on NNP or nosuid if not an allowed transition. */ + rc = check_nnp_nosuid(bprm, old_tsec, new_tsec); + if (rc) + return rc; } else { /* Check for a default transition on this program. */ rc = security_transition_sid(old_tsec->sid, isec->sid, @@ -2148,15 +2179,19 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) &new_tsec->sid); if (rc) return rc; + + /* + * Fallback to old SID on NNP or nosuid if not an allowed + * transition. + */ + rc = check_nnp_nosuid(bprm, old_tsec, new_tsec); + if (rc) + new_tsec->sid = old_tsec->sid; } ad.type = LSM_AUDIT_DATA_PATH; ad.u.path = bprm->file->f_path; - if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) || - (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) - new_tsec->sid = old_tsec->sid; - if (new_tsec->sid == old_tsec->sid) { rc = avc_has_perm(old_tsec->sid, isec->sid, SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); -- GitLab From a492f075450f3ba87de36e5ffe92a9d0c7af9723 Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Thu, 28 Aug 2014 08:15:21 -0600 Subject: [PATCH 0753/5088] block,scsi: fixup blk_get_request dead queue scenarios The blk_get_request function may fail in low-memory conditions or during device removal (even if __GFP_WAIT is set). To distinguish between these errors, modify the blk_get_request call stack to return the appropriate ERR_PTR. Verify that all callers check the return status and consider IS_ERR instead of a simple NULL pointer check. For consistency, make a similar change to the blk_mq_alloc_request leg of blk_get_request. It may fail if the queue is dead, or the caller was unwilling to wait. Signed-off-by: Joe Lawrence Acked-by: Jiri Kosina [for pktdvd] Acked-by: Boaz Harrosh [for osd] Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe --- block/blk-core.c | 34 ++++++++++----------- block/blk-mq.c | 8 +++-- block/bsg.c | 8 ++--- block/scsi_ioctl.c | 12 ++++---- drivers/block/paride/pd.c | 4 +-- drivers/block/pktcdvd.c | 4 +-- drivers/block/sx8.c | 2 +- drivers/cdrom/cdrom.c | 4 +-- drivers/ide/ide-park.c | 2 +- drivers/scsi/device_handler/scsi_dh_alua.c | 2 +- drivers/scsi/device_handler/scsi_dh_emc.c | 2 +- drivers/scsi/device_handler/scsi_dh_hp_sw.c | 4 +-- drivers/scsi/device_handler/scsi_dh_rdac.c | 2 +- drivers/scsi/osd/osd_initiator.c | 4 +-- drivers/scsi/osst.c | 2 +- drivers/scsi/scsi_error.c | 2 +- drivers/scsi/scsi_lib.c | 2 +- drivers/scsi/sg.c | 4 +-- drivers/scsi/st.c | 2 +- drivers/target/target_core_pscsi.c | 2 +- 20 files changed, 55 insertions(+), 51 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index c359d72e9d76..93603e6ff479 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -933,9 +933,9 @@ static struct io_context *rq_ioc(struct bio *bio) * Get a free request from @q. This function may fail under memory * pressure or if @q is dead. * - * Must be callled with @q->queue_lock held and, - * Returns %NULL on failure, with @q->queue_lock held. - * Returns !%NULL on success, with @q->queue_lock *not held*. + * Must be called with @q->queue_lock held and, + * Returns ERR_PTR on failure, with @q->queue_lock held. + * Returns request pointer on success, with @q->queue_lock *not held*. */ static struct request *__get_request(struct request_list *rl, int rw_flags, struct bio *bio, gfp_t gfp_mask) @@ -949,7 +949,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags, int may_queue; if (unlikely(blk_queue_dying(q))) - return NULL; + return ERR_PTR(-ENODEV); may_queue = elv_may_queue(q, rw_flags); if (may_queue == ELV_MQUEUE_NO) @@ -974,7 +974,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags, * process is not a "batcher", and not * exempted by the IO scheduler */ - return NULL; + return ERR_PTR(-ENOMEM); } } } @@ -992,7 +992,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags, * allocated with any setting of ->nr_requests */ if (rl->count[is_sync] >= (3 * q->nr_requests / 2)) - return NULL; + return ERR_PTR(-ENOMEM); q->nr_rqs[is_sync]++; rl->count[is_sync]++; @@ -1097,7 +1097,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags, rq_starved: if (unlikely(rl->count[is_sync] == 0)) rl->starved[is_sync] = 1; - return NULL; + return ERR_PTR(-ENOMEM); } /** @@ -1110,9 +1110,9 @@ static struct request *__get_request(struct request_list *rl, int rw_flags, * Get a free request from @q. If %__GFP_WAIT is set in @gfp_mask, this * function keeps retrying under memory pressure and fails iff @q is dead. * - * Must be callled with @q->queue_lock held and, - * Returns %NULL on failure, with @q->queue_lock held. - * Returns !%NULL on success, with @q->queue_lock *not held*. + * Must be called with @q->queue_lock held and, + * Returns ERR_PTR on failure, with @q->queue_lock held. + * Returns request pointer on success, with @q->queue_lock *not held*. */ static struct request *get_request(struct request_queue *q, int rw_flags, struct bio *bio, gfp_t gfp_mask) @@ -1125,12 +1125,12 @@ static struct request *get_request(struct request_queue *q, int rw_flags, rl = blk_get_rl(q, bio); /* transferred to @rq on success */ retry: rq = __get_request(rl, rw_flags, bio, gfp_mask); - if (rq) + if (!IS_ERR(rq)) return rq; if (!(gfp_mask & __GFP_WAIT) || unlikely(blk_queue_dying(q))) { blk_put_rl(rl); - return NULL; + return rq; } /* wait on @rl and retry */ @@ -1167,7 +1167,7 @@ static struct request *blk_old_get_request(struct request_queue *q, int rw, spin_lock_irq(q->queue_lock); rq = get_request(q, rw, NULL, gfp_mask); - if (!rq) + if (IS_ERR(rq)) spin_unlock_irq(q->queue_lock); /* q->queue_lock is unlocked at this point */ @@ -1219,8 +1219,8 @@ struct request *blk_make_request(struct request_queue *q, struct bio *bio, { struct request *rq = blk_get_request(q, bio_data_dir(bio), gfp_mask); - if (unlikely(!rq)) - return ERR_PTR(-ENOMEM); + if (IS_ERR(rq)) + return rq; blk_rq_set_block_pc(rq); @@ -1615,8 +1615,8 @@ void blk_queue_bio(struct request_queue *q, struct bio *bio) * Returns with the queue unlocked. */ req = get_request(q, rw_flags, bio, GFP_NOIO); - if (unlikely(!req)) { - bio_endio(bio, -ENODEV); /* @q is dead */ + if (IS_ERR(req)) { + bio_endio(bio, PTR_ERR(req)); /* @q is dead */ goto out_unlock; } diff --git a/block/blk-mq.c b/block/blk-mq.c index 5189cb1e478a..940aa8a34b70 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -218,9 +218,11 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp, struct blk_mq_hw_ctx *hctx; struct request *rq; struct blk_mq_alloc_data alloc_data; + int ret; - if (blk_mq_queue_enter(q)) - return NULL; + ret = blk_mq_queue_enter(q); + if (ret) + return ERR_PTR(ret); ctx = blk_mq_get_ctx(q); hctx = q->mq_ops->map_queue(q, ctx->cpu); @@ -240,6 +242,8 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp, ctx = alloc_data.ctx; } blk_mq_put_ctx(ctx); + if (!rq) + return ERR_PTR(-EWOULDBLOCK); return rq; } EXPORT_SYMBOL(blk_mq_alloc_request); diff --git a/block/bsg.c b/block/bsg.c index ff46addde5d8..73c78fd12cc1 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -270,8 +270,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm, * map scatter-gather elements separately and string them to request */ rq = blk_get_request(q, rw, GFP_KERNEL); - if (!rq) - return ERR_PTR(-ENOMEM); + if (IS_ERR(rq)) + return rq; blk_rq_set_block_pc(rq); ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd, has_write_perm); @@ -285,8 +285,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm, } next_rq = blk_get_request(q, READ, GFP_KERNEL); - if (!next_rq) { - ret = -ENOMEM; + if (IS_ERR(next_rq)) { + ret = PTR_ERR(next_rq); goto out; } rq->next_rq = next_rq; diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 29d056782833..a8b0d0208448 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -318,8 +318,8 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk, at_head = 1; rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); - if (!rq) - return -ENOMEM; + if (IS_ERR(rq)) + return PTR_ERR(rq); blk_rq_set_block_pc(rq); if (blk_fill_sghdr_rq(q, rq, hdr, mode)) { @@ -448,8 +448,8 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, } rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT); - if (!rq) { - err = -ENODEV; + if (IS_ERR(rq)) { + err = PTR_ERR(rq); goto error_free_buffer; } @@ -539,8 +539,8 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, int err; rq = blk_get_request(q, WRITE, __GFP_WAIT); - if (!rq) - return -ENODEV; + if (IS_ERR(rq)) + return PTR_ERR(rq); blk_rq_set_block_pc(rq); rq->timeout = BLK_DEFAULT_SG_TIMEOUT; rq->cmd[0] = cmd; diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index ca831f741d89..d48715b287e6 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -722,8 +722,8 @@ static int pd_special_command(struct pd_unit *disk, int err = 0; rq = blk_get_request(disk->gd->queue, READ, __GFP_WAIT); - if (!rq) - return -ENODEV; + if (IS_ERR(rq)) + return PTR_ERR(rq); rq->cmd_type = REQ_TYPE_SPECIAL; rq->special = func; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 7fa8c80e8982..09e628dafd9d 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -704,8 +704,8 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ, __GFP_WAIT); - if (!rq) - return -ENODEV; + if (IS_ERR(rq)) + return PTR_ERR(rq); blk_rq_set_block_pc(rq); if (cgc->buflen) { diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index d5e2d12b9d9e..5d552857de41 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -568,7 +568,7 @@ static struct carm_request *carm_get_special(struct carm_host *host) return NULL; rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL); - if (!rq) { + if (IS_ERR(rq)) { spin_lock_irqsave(&host->lock, flags); carm_put_request(host, crq); spin_unlock_irqrestore(&host->lock, flags); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 898b84bba28a..5d28a45d2960 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2180,8 +2180,8 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, len = nr * CD_FRAMESIZE_RAW; rq = blk_get_request(q, READ, GFP_KERNEL); - if (!rq) { - ret = -ENOMEM; + if (IS_ERR(rq)) { + ret = PTR_ERR(rq); break; } blk_rq_set_block_pc(rq); diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c index f41558a0bcd1..ca958604cda2 100644 --- a/drivers/ide/ide-park.c +++ b/drivers/ide/ide-park.c @@ -46,7 +46,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) * timeout has expired, so power management will be reenabled. */ rq = blk_get_request(q, READ, GFP_NOWAIT); - if (unlikely(!rq)) + if (IS_ERR(rq)) goto out; rq->cmd[0] = REQ_UNPARK_HEADS; diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 7bcf67eec921..e99507ed0e3c 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -115,7 +115,7 @@ static struct request *get_alua_req(struct scsi_device *sdev, rq = blk_get_request(q, rw, GFP_NOIO); - if (!rq) { + if (IS_ERR(rq)) { sdev_printk(KERN_INFO, sdev, "%s: blk_get_request failed\n", __func__); return NULL; diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 6f07f7fe3aa1..84765384c47c 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -275,7 +275,7 @@ static struct request *get_req(struct scsi_device *sdev, int cmd, rq = blk_get_request(sdev->request_queue, (cmd != INQUIRY) ? WRITE : READ, GFP_NOIO); - if (!rq) { + if (IS_ERR(rq)) { sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); return NULL; } diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index e9d9fea9e272..4ee2759f5299 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -117,7 +117,7 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) retry: req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); - if (!req) + if (IS_ERR(req)) return SCSI_DH_RES_TEMP_UNAVAIL; blk_rq_set_block_pc(req); @@ -247,7 +247,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h) struct request *req; req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC); - if (!req) + if (IS_ERR(req)) return SCSI_DH_RES_TEMP_UNAVAIL; blk_rq_set_block_pc(req); diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 826069db9848..1b5bc9293e37 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -274,7 +274,7 @@ static struct request *get_rdac_req(struct scsi_device *sdev, rq = blk_get_request(q, rw, GFP_NOIO); - if (!rq) { + if (IS_ERR(rq)) { sdev_printk(KERN_INFO, sdev, "get_rdac_req: blk_get_request failed.\n"); return NULL; diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 5f4cbf0c4759..fd19fd8468ac 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -1567,8 +1567,8 @@ static struct request *_make_request(struct request_queue *q, bool has_write, struct request *req; req = blk_get_request(q, has_write ? WRITE : READ, flags); - if (unlikely(!req)) - return ERR_PTR(-ENOMEM); + if (IS_ERR(req)) + return req; blk_rq_set_block_pc(req); return req; diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 0727ea7cc387..dff37a250d79 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -362,7 +362,7 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, int write = (data_direction == DMA_TO_DEVICE); req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL); - if (!req) + if (IS_ERR(req)) return DRIVER_ERROR << 24; blk_rq_set_block_pc(req); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 4c433bf47a06..a2c3d3d255a1 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1960,7 +1960,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) * request becomes available */ req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL); - if (!req) + if (IS_ERR(req)) return; blk_rq_set_block_pc(req); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ce62e8798cc8..972d0a8adf2e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -221,7 +221,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int ret = DRIVER_ERROR << 24; req = blk_get_request(sdev->request_queue, write, __GFP_WAIT); - if (!req) + if (IS_ERR(req)) return ret; blk_rq_set_block_pc(req); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 01cf88888797..60354449d9ed 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1711,9 +1711,9 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) } rq = blk_get_request(q, rw, GFP_ATOMIC); - if (!rq) { + if (IS_ERR(rq)) { kfree(long_cmdp); - return -ENOMEM; + return PTR_ERR(rq); } blk_rq_set_block_pc(rq); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index aff9689de0f7..59db5bfc11db 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -490,7 +490,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL); - if (!req) + if (IS_ERR(req)) return DRIVER_ERROR << 24; blk_rq_set_block_pc(req); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 943b1dbe859a..70d9f6dabba0 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -1050,7 +1050,7 @@ pscsi_execute_cmd(struct se_cmd *cmd) req = blk_get_request(pdv->pdv_sd->request_queue, (data_direction == DMA_TO_DEVICE), GFP_KERNEL); - if (!req) { + if (IS_ERR(req)) { pr_err("PSCSI: blk_get_request() failed\n"); ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto fail; -- GitLab From 98c5d36240e10c2e0e06e2bb10496291626d1d43 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Thu, 28 Aug 2014 10:54:08 -0500 Subject: [PATCH 0754/5088] ASoC: cs4265: Add CHIP_ID as a readable register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Zoltán Szenczi Signed-off-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index a20b30ca52c0..2dad15ae0530 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -77,6 +77,7 @@ static bool cs4265_readable_register(struct device *dev, unsigned int reg) case CS4265_INT_MASK: case CS4265_STATUS_MODE_MSB: case CS4265_STATUS_MODE_LSB: + case CS4265_CHIP_ID: return true; default: return false; -- GitLab From 7eef08554ca35454e6da0de8a74f7c96bc2e58e0 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 28 Aug 2014 10:02:40 -0500 Subject: [PATCH 0755/5088] ASoC: cs35l32: use true/false returns for bool functions Return true or false instead of 1 and 0 Reported-by: Fengguang Wu Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 9c6b2723d343..ca897c49afdf 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -121,9 +121,9 @@ static bool cs35l32_volatile_register(struct device *dev, unsigned int reg) case CS35L32_INT_STATUS_2: case CS35L32_INT_STATUS_3: case CS35L32_LED_STATUS: - return 1; + return true; default: - return 0; + return false; } } @@ -134,9 +134,9 @@ static bool cs35l32_precious_register(struct device *dev, unsigned int reg) case CS35L32_INT_STATUS_2: case CS35L32_INT_STATUS_3: case CS35L32_LED_STATUS: - return 1; + return true; default: - return 0; + return false; } } -- GitLab From 5c216cc3f37a6eecb4e12ab0248b66e6386da0fe Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 28 Aug 2014 10:02:41 -0500 Subject: [PATCH 0756/5088] ASoC: cs42l52: use true/false returns for bool functions Return true or false instead of 1 and 0 Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 969167d8b71e..da4f758cd12a 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -176,9 +176,9 @@ static bool cs42l52_volatile_register(struct device *dev, unsigned int reg) case CS42L52_BATT_LEVEL: case CS42L52_SPK_STATUS: case CS42L52_CHARGE_PUMP: - return 1; + return true; default: - return 0; + return false; } } -- GitLab From c2b49ae678b8bd1fd4ea3e3ae106020d663e8969 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 28 Aug 2014 10:02:42 -0500 Subject: [PATCH 0757/5088] ASoC: cs42l56: use true/false returns for bool functions Return true or false instead of 1 and 0 Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index c766a5a9ce80..b1c7396c80c8 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -171,9 +171,9 @@ static bool cs42l56_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case CS42L56_INT_STATUS: - return 1; + return true; default: - return 0; + return false; } } -- GitLab From b792346fa8660a22a06f118cebe47709f507914f Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 28 Aug 2014 14:07:11 +0300 Subject: [PATCH 0758/5088] ASoC: Remove unused cache_only from struct snd_soc_codec There are no real users for cache_only in "struct snd_soc_codec" so remove it and needless debugfs node. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - sound/soc/soc-core.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index edbb0d72ab38..ce09302bfd6d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -792,7 +792,6 @@ struct snd_soc_codec { unsigned int ac97_registered:1; /* Codec has been AC97 registered */ unsigned int ac97_created:1; /* Codec has been created by SoC */ unsigned int cache_init:1; /* codec cache has been initialized */ - u32 cache_only; /* Suppress writes to hardware */ u32 cache_sync; /* Cache needs to be synced to hardware */ /* codec IO */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 419682693886..1b422c5c36c8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -311,8 +311,6 @@ static void soc_init_codec_debugfs(struct snd_soc_component *component) debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, &codec->cache_sync); - debugfs_create_bool("cache_only", 0444, codec->component.debugfs_root, - &codec->cache_only); codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, codec->component.debugfs_root, -- GitLab From 1a83269d5c41b77f2a4bbb3828c668c96832742e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 28 Aug 2014 17:54:38 +0800 Subject: [PATCH 0759/5088] ASoC: cs35l32: Remove unneeded regulator_bulk_free call in cs35l32_i2c_remove The regulator_bulk_free() call is not required because current code is using devm_regulator_bulk_get(). Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index ca897c49afdf..b32d7a9d0c0f 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -562,8 +562,6 @@ static int cs35l32_i2c_remove(struct i2c_client *i2c_client) if (cs35l32->reset_gpio) gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); - regulator_bulk_free(ARRAY_SIZE(cs35l32->supplies), cs35l32->supplies); - return 0; } -- GitLab From a4f87cea72d78f80c0bda1b4d8a821278eb1e4e2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 28 Aug 2014 17:55:20 +0800 Subject: [PATCH 0760/5088] ASoC: cs42l56: Remove unneeded regulator_bulk_free call in cs42l56_remove The regulator_bulk_free() call is not required because current code is using devm_regulator_bulk_get(). Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index b1c7396c80c8..bb74dd17fa26 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1175,11 +1175,8 @@ static int cs42l56_probe(struct snd_soc_codec *codec) static int cs42l56_remove(struct snd_soc_codec *codec) { - struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); - cs42l56_free_beep(codec); cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies); return 0; } -- GitLab From 5f609f282b59f111840e755bac8da980387e044e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 28 Aug 2014 16:27:56 +0800 Subject: [PATCH 0761/5088] ASoC: cs35l32: Simplify implementation of cs35l32_codec_set_sysclk Use single snd_soc_update_bits() call to update the register bits. Signed-off-by: Axel Lin Tested-by: Brian Austin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index b32d7a9d0c0f..76f628bd7f2b 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -242,41 +242,27 @@ static struct snd_soc_dai_driver cs35l32_dai[] = { static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { + unsigned int val; switch (freq) { case 6000000: - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_DIV2_MASK, 0); - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_RATIO_MASK, - CS35L32_MCLK_RATIO); + val = CS35L32_MCLK_RATIO; break; case 12000000: - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_DIV2_MASK, - CS35L32_MCLK_DIV2_MASK); - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_RATIO_MASK, - CS35L32_MCLK_RATIO); + val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO; break; case 6144000: - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_DIV2_MASK, 0); - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_RATIO_MASK, 0); + val = 0; break; case 12288000: - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_DIV2_MASK, - CS35L32_MCLK_DIV2_MASK); - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_RATIO_MASK, 0); + val = CS35L32_MCLK_DIV2_MASK; break; default: return -EINVAL; } - return 0; + return snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val); } static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { -- GitLab From d166c8024d620d654b12834fac354fb4203c6c22 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 27 Aug 2014 14:51:27 -0700 Subject: [PATCH 0762/5088] Smack: Bring-up access mode People keep asking me for permissive mode, and I keep saying "no". Permissive mode is wrong for more reasons than I can enumerate, but the compelling one is that it's once on, never off. Nonetheless, there is an argument to be made for running a process with lots of permissions, logging which are required, and then locking the process down. There wasn't a way to do that with Smack, but this provides it. The notion is that you start out by giving the process an appropriate Smack label, such as "ATBirds". You create rules with a wide range of access and the "b" mode. On Tizen it might be: ATBirds System rwxalb ATBirds User rwxalb ATBirds _ rwxalb User ATBirds wb System ATBirds wb Accesses that fail will generate audit records. Accesses that succeed because of rules marked with a "b" generate log messages identifying the rule, the program and as much object information as is convenient. When the system is properly configured and the programs brought in line with the labeling scheme the "b" mode can be removed from the rules. When the system is ready for production the facility can be configured out. This provides the developer the convenience of permissive mode without creating a system that looks like it is enforcing a policy while it is not. Signed-off-by: Casey Schaufler --- security/smack/Kconfig | 16 ++ security/smack/smack.h | 5 +- security/smack/smack_access.c | 24 ++- security/smack/smack_lsm.c | 265 +++++++++++++++++++++++++++++++--- security/smack/smackfs.c | 11 +- 5 files changed, 294 insertions(+), 27 deletions(-) diff --git a/security/smack/Kconfig b/security/smack/Kconfig index e69de9c642b7..b065f9789418 100644 --- a/security/smack/Kconfig +++ b/security/smack/Kconfig @@ -12,3 +12,19 @@ config SECURITY_SMACK of other mandatory security schemes. If you are unsure how to answer this question, answer N. +config SECURITY_SMACK_BRINGUP + bool "Reporting on access granted by Smack rules" + depends on SECURITY_SMACK + default n + help + Enable the bring-up ("b") access mode in Smack rules. + When access is granted by a rule with the "b" mode a + message about the access requested is generated. The + intention is that a process can be granted a wide set + of access initially with the bringup mode set on the + rules. The developer can use the information to + identify which rules are necessary and what accesses + may be inappropriate. The developer can reduce the + access rule set once the behavior is well understood. + This is a superior mechanism to the oft abused + "permissive" mode of other systems. diff --git a/security/smack/smack.h b/security/smack/smack.h index 020307ef0972..2d13d5fb17ed 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -191,6 +191,7 @@ struct smk_port_label { */ #define MAY_TRANSMUTE 0x00001000 /* Controls directory labeling */ #define MAY_LOCK 0x00002000 /* Locks should be writes, but ... */ +#define MAY_BRINGUP 0x00004000 /* Report use of this rule */ /* * Just to make the common cases easier to deal with @@ -200,9 +201,9 @@ struct smk_port_label { #define MAY_NOT 0 /* - * Number of access types used by Smack (rwxatl) + * Number of access types used by Smack (rwxatlb) */ -#define SMK_NUM_ACCESS_TYPE 6 +#define SMK_NUM_ACCESS_TYPE 7 /* SMACK data */ struct smack_audit_data { diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index f97d0842e621..9f02cb0ac85e 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -178,16 +178,27 @@ int smk_access(struct smack_known *subject_known, char *object_label, &subject_known->smk_rules); rcu_read_unlock(); - if (may > 0 && (request & may) == request) + if (may <= 0 || (request & may) != request) { + rc = -EACCES; goto out_audit; + } +#ifdef CONFIG_SECURITY_SMACK_BRINGUP + /* + * Return a positive value if using bringup mode. + * This allows the hooks to identify checks that + * succeed because of "b" rules. + */ + if (may & MAY_BRINGUP) + rc = MAY_BRINGUP; +#endif - rc = -EACCES; out_audit: #ifdef CONFIG_AUDIT if (a) smack_log(subject_known->smk_known, object_label, request, rc, a); #endif + return rc; } @@ -214,7 +225,7 @@ int smk_tskacc(struct task_smack *subject, char *obj_label, * Check the global rule list */ rc = smk_access(skp, obj_label, mode, NULL); - if (rc == 0) { + if (rc >= 0) { /* * If there is an entry in the task's rule list * it can further restrict access. @@ -328,6 +339,13 @@ void smack_log(char *subject_label, char *object_label, int request, struct smack_audit_data *sad; struct common_audit_data *a = &ad->a; +#ifdef CONFIG_SECURITY_SMACK_BRINGUP + /* + * The result may be positive in bringup mode. + */ + if (result > 0) + result = 0; +#endif /* check if we have to log the current event */ if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0) return; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 7091b46adab2..154548ea7d87 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -54,6 +54,149 @@ LIST_HEAD(smk_ipv6_port_list); +#ifdef CONFIG_SECURITY_SMACK_BRINGUP +static void smk_bu_mode(int mode, char *s) +{ + int i = 0; + + if (mode & MAY_READ) + s[i++] = 'r'; + if (mode & MAY_WRITE) + s[i++] = 'w'; + if (mode & MAY_EXEC) + s[i++] = 'x'; + if (mode & MAY_APPEND) + s[i++] = 'a'; + if (mode & MAY_TRANSMUTE) + s[i++] = 't'; + if (mode & MAY_LOCK) + s[i++] = 'l'; + if (i == 0) + s[i++] = '-'; + s[i] = '\0'; +} +#endif + +#ifdef CONFIG_SECURITY_SMACK_BRINGUP +static int smk_bu_note(char *note, struct smack_known *sskp, char *osp, + int mode, int rc) +{ + char acc[SMK_NUM_ACCESS_TYPE + 1]; + + if (rc <= 0) + return rc; + + smk_bu_mode(mode, acc); + pr_info("Smack Bringup: (%s %s %s) %s\n", + sskp->smk_known, osp, acc, note); + return 0; +} +#else +#define smk_bu_note(note, sskp, osp, mode, RC) (RC) +#endif + +#ifdef CONFIG_SECURITY_SMACK_BRINGUP +static int smk_bu_current(char *note, char *osp, int mode, int rc) +{ + struct task_smack *tsp = current_security(); + char acc[SMK_NUM_ACCESS_TYPE + 1]; + + if (rc <= 0) + return rc; + + smk_bu_mode(mode, acc); + pr_info("Smack Bringup: (%s %s %s) %s %s\n", + tsp->smk_task->smk_known, osp, acc, current->comm, note); + return 0; +} +#else +#define smk_bu_current(note, osp, mode, RC) (RC) +#endif + +#ifdef CONFIG_SECURITY_SMACK_BRINGUP +static int smk_bu_task(struct task_struct *otp, int mode, int rc) +{ + struct task_smack *tsp = current_security(); + struct task_smack *otsp = task_security(otp); + char acc[SMK_NUM_ACCESS_TYPE + 1]; + + if (rc <= 0) + return rc; + + smk_bu_mode(mode, acc); + pr_info("Smack Bringup: (%s %s %s) %s to %s\n", + tsp->smk_task->smk_known, otsp->smk_task->smk_known, acc, + current->comm, otp->comm); + return 0; +} +#else +#define smk_bu_task(otp, mode, RC) (RC) +#endif + +#ifdef CONFIG_SECURITY_SMACK_BRINGUP +static int smk_bu_inode(struct inode *inode, int mode, int rc) +{ + struct task_smack *tsp = current_security(); + char acc[SMK_NUM_ACCESS_TYPE + 1]; + + if (rc <= 0) + return rc; + + smk_bu_mode(mode, acc); + pr_info("Smack Bringup: (%s %s %s) inode=(%s %ld) %s\n", + tsp->smk_task->smk_known, smk_of_inode(inode), acc, + inode->i_sb->s_id, inode->i_ino, current->comm); + return 0; +} +#else +#define smk_bu_inode(inode, mode, RC) (RC) +#endif + +#ifdef CONFIG_SECURITY_SMACK_BRINGUP +static int smk_bu_file(struct file *file, int mode, int rc) +{ + struct task_smack *tsp = current_security(); + struct smack_known *sskp = tsp->smk_task; + struct inode *inode = file->f_inode; + char acc[SMK_NUM_ACCESS_TYPE + 1]; + + if (rc <= 0) + return rc; + + smk_bu_mode(mode, acc); + pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n", + sskp->smk_known, (char *)file->f_security, acc, + inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name, + current->comm); + return 0; +} +#else +#define smk_bu_file(file, mode, RC) (RC) +#endif + +#ifdef CONFIG_SECURITY_SMACK_BRINGUP +static int smk_bu_credfile(const struct cred *cred, struct file *file, + int mode, int rc) +{ + struct task_smack *tsp = cred->security; + struct smack_known *sskp = tsp->smk_task; + struct inode *inode = file->f_inode; + char acc[SMK_NUM_ACCESS_TYPE + 1]; + + if (rc <= 0) + return rc; + + smk_bu_mode(mode, acc); + pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n", + sskp->smk_known, smk_of_inode(inode), acc, + inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name, + current->comm); + return 0; +} +#else +#define smk_bu_credfile(cred, file, mode, RC) (RC) +#endif + /** * smk_fetch - Fetch the smack label from a file. * @ip: a pointer to the inode @@ -507,6 +650,7 @@ static int smack_sb_statfs(struct dentry *dentry) smk_ad_setfield_u_fs_path_dentry(&ad, dentry); rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); + rc = smk_bu_current("statfs", sbp->smk_floor, MAY_READ, rc); return rc; } @@ -697,11 +841,13 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, isp = smk_of_inode(old_dentry->d_inode); rc = smk_curacc(isp, MAY_WRITE, &ad); + rc = smk_bu_inode(old_dentry->d_inode, MAY_WRITE, rc); if (rc == 0 && new_dentry->d_inode != NULL) { isp = smk_of_inode(new_dentry->d_inode); smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); rc = smk_curacc(isp, MAY_WRITE, &ad); + rc = smk_bu_inode(new_dentry->d_inode, MAY_WRITE, rc); } return rc; @@ -728,6 +874,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) * You need write access to the thing you're unlinking */ rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad); + rc = smk_bu_inode(ip, MAY_WRITE, rc); if (rc == 0) { /* * You also need write access to the containing directory @@ -735,6 +882,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, dir); rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); + rc = smk_bu_inode(dir, MAY_WRITE, rc); } return rc; } @@ -759,6 +907,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) * You need write access to the thing you're removing */ rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); + rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc); if (rc == 0) { /* * You also need write access to the containing directory @@ -766,6 +915,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, dir); rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); + rc = smk_bu_inode(dir, MAY_WRITE, rc); } return rc; @@ -797,11 +947,13 @@ static int smack_inode_rename(struct inode *old_inode, isp = smk_of_inode(old_dentry->d_inode); rc = smk_curacc(isp, MAY_READWRITE, &ad); + rc = smk_bu_inode(old_dentry->d_inode, MAY_READWRITE, rc); if (rc == 0 && new_dentry->d_inode != NULL) { isp = smk_of_inode(new_dentry->d_inode); smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); rc = smk_curacc(isp, MAY_READWRITE, &ad); + rc = smk_bu_inode(new_dentry->d_inode, MAY_READWRITE, rc); } return rc; } @@ -819,6 +971,7 @@ static int smack_inode_permission(struct inode *inode, int mask) { struct smk_audit_info ad; int no_block = mask & MAY_NOT_BLOCK; + int rc; mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); /* @@ -832,7 +985,9 @@ static int smack_inode_permission(struct inode *inode, int mask) return -ECHILD; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, inode); - return smk_curacc(smk_of_inode(inode), mask, &ad); + rc = smk_curacc(smk_of_inode(inode), mask, &ad); + rc = smk_bu_inode(inode, mask, rc); + return rc; } /** @@ -845,6 +1000,8 @@ static int smack_inode_permission(struct inode *inode, int mask) static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) { struct smk_audit_info ad; + int rc; + /* * Need to allow for clearing the setuid bit. */ @@ -853,7 +1010,9 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); + rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc); + return rc; } /** @@ -867,13 +1026,16 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) { struct smk_audit_info ad; struct path path; + int rc; path.dentry = dentry; path.mnt = mnt; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, path); - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); + rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); + rc = smk_bu_inode(dentry->d_inode, MAY_READ, rc); + return rc; } /** @@ -932,8 +1094,10 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); - if (rc == 0) + if (rc == 0) { rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); + rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc); + } return rc; } @@ -993,11 +1157,14 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, static int smack_inode_getxattr(struct dentry *dentry, const char *name) { struct smk_audit_info ad; + int rc; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); + rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); + rc = smk_bu_inode(dentry->d_inode, MAY_READ, rc); + return rc; } /** @@ -1033,6 +1200,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) smk_ad_setfield_u_fs_path_dentry(&ad, dentry); rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); + rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc); if (rc != 0) return rc; @@ -1213,11 +1381,15 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - if (_IOC_DIR(cmd) & _IOC_WRITE) + if (_IOC_DIR(cmd) & _IOC_WRITE) { rc = smk_curacc(file->f_security, MAY_WRITE, &ad); + rc = smk_bu_file(file, MAY_WRITE, rc); + } - if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) + if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) { rc = smk_curacc(file->f_security, MAY_READ, &ad); + rc = smk_bu_file(file, MAY_READ, rc); + } return rc; } @@ -1232,10 +1404,13 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, static int smack_file_lock(struct file *file, unsigned int cmd) { struct smk_audit_info ad; + int rc; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - return smk_curacc(file->f_security, MAY_LOCK, &ad); + rc = smk_curacc(file->f_security, MAY_LOCK, &ad); + rc = smk_bu_file(file, MAY_LOCK, rc); + return rc; } /** @@ -1265,12 +1440,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); rc = smk_curacc(file->f_security, MAY_LOCK, &ad); + rc = smk_bu_file(file, MAY_LOCK, rc); break; case F_SETOWN: case F_SETSIG: smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); rc = smk_curacc(file->f_security, MAY_WRITE, &ad); + rc = smk_bu_file(file, MAY_WRITE, rc); break; default: break; @@ -1425,6 +1602,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, /* we don't log here as rc can be overriden */ skp = smk_find_entry(file->f_security); rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL); + rc = smk_bu_note("sigiotask", skp, tkp->smk_known, MAY_WRITE, rc); if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) rc = 0; @@ -1442,6 +1620,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, */ static int smack_file_receive(struct file *file) { + int rc; int may = 0; struct smk_audit_info ad; @@ -1455,7 +1634,9 @@ static int smack_file_receive(struct file *file) if (file->f_mode & FMODE_WRITE) may |= MAY_WRITE; - return smk_curacc(file->f_security, may, &ad); + rc = smk_curacc(file->f_security, may, &ad); + rc = smk_bu_file(file, may, rc); + return rc; } /** @@ -1485,6 +1666,7 @@ static int smack_file_open(struct file *file, const struct cred *cred) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad); + rc = smk_bu_credfile(cred, file, MAY_READ, rc); if (rc == 0) file->f_security = isp->smk_inode; @@ -1641,10 +1823,13 @@ static int smk_curacc_on_task(struct task_struct *p, int access, { struct smk_audit_info ad; struct smack_known *skp = smk_of_task(task_security(p)); + int rc; smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); - return smk_curacc(skp->smk_known, access, &ad); + rc = smk_curacc(skp->smk_known, access, &ad); + rc = smk_bu_task(p, access, rc); + return rc; } /** @@ -1798,6 +1983,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, struct smk_audit_info ad; struct smack_known *skp; struct smack_known *tkp = smk_of_task(task_security(p)); + int rc; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); @@ -1805,15 +1991,20 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * Sending a signal requires that the sender * can write the receiver. */ - if (secid == 0) - return smk_curacc(tkp->smk_known, MAY_WRITE, &ad); + if (secid == 0) { + rc = smk_curacc(tkp->smk_known, MAY_WRITE, &ad); + rc = smk_bu_task(p, MAY_WRITE, rc); + return rc; + } /* * If the secid isn't 0 we're dealing with some USB IO * specific behavior. This is not clean. For one thing * we can't take privilege into account. */ skp = smack_from_secid(secid); - return smk_access(skp, tkp->smk_known, MAY_WRITE, &ad); + rc = smk_access(skp, tkp->smk_known, MAY_WRITE, &ad); + rc = smk_bu_note("USB signal", skp, tkp->smk_known, MAY_WRITE, rc); + return rc; } /** @@ -2005,6 +2196,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) sk_lbl = SMACK_UNLABELED_SOCKET; skp = ssp->smk_out; rc = smk_access(skp, hostsp, MAY_WRITE, &ad); + rc = smk_bu_note("IPv4 host check", skp, hostsp, MAY_WRITE, rc); } else { sk_lbl = SMACK_CIPSO_SOCKET; rc = 0; @@ -2107,6 +2299,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, unsigned short port = 0; char *object; struct smk_audit_info ad; + int rc; #ifdef CONFIG_AUDIT struct lsm_network_audit net; #endif @@ -2160,7 +2353,9 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, else ad.a.u.net->v6info.daddr = address->sin6_addr; #endif - return smk_access(skp, object, MAY_WRITE, &ad); + rc = smk_access(skp, object, MAY_WRITE, &ad); + rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc); + return rc; } /** @@ -2399,12 +2594,15 @@ static int smk_curacc_shm(struct shmid_kernel *shp, int access) { char *ssp = smack_of_shm(shp); struct smk_audit_info ad; + int rc; #ifdef CONFIG_AUDIT smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); ad.a.u.ipc_id = shp->shm_perm.id; #endif - return smk_curacc(ssp, access, &ad); + rc = smk_curacc(ssp, access, &ad); + rc = smk_bu_current("shm", ssp, access, rc); + return rc; } /** @@ -2523,12 +2721,15 @@ static int smk_curacc_sem(struct sem_array *sma, int access) { char *ssp = smack_of_sem(sma); struct smk_audit_info ad; + int rc; #ifdef CONFIG_AUDIT smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); ad.a.u.ipc_id = sma->sem_perm.id; #endif - return smk_curacc(ssp, access, &ad); + rc = smk_curacc(ssp, access, &ad); + rc = smk_bu_current("sem", ssp, access, rc); + return rc; } /** @@ -2653,12 +2854,15 @@ static int smk_curacc_msq(struct msg_queue *msq, int access) { char *msp = smack_of_msq(msq); struct smk_audit_info ad; + int rc; #ifdef CONFIG_AUDIT smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); ad.a.u.ipc_id = msq->q_perm.id; #endif - return smk_curacc(msp, access, &ad); + rc = smk_curacc(msp, access, &ad); + rc = smk_bu_current("msq", msp, access, rc); + return rc; } /** @@ -2754,12 +2958,15 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) char *isp = ipp->security; int may = smack_flags_to_may(flag); struct smk_audit_info ad; + int rc; #ifdef CONFIG_AUDIT smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); ad.a.u.ipc_id = ipp->id; #endif - return smk_curacc(isp, may, &ad); + rc = smk_curacc(isp, may, &ad); + rc = smk_bu_current("svipc", isp, may, rc); + return rc; } /** @@ -3092,8 +3299,13 @@ static int smack_unix_stream_connect(struct sock *sock, smk_ad_setfield_u_net_sk(&ad, other); #endif rc = smk_access(skp, okp->smk_known, MAY_WRITE, &ad); - if (rc == 0) + rc = smk_bu_note("UDS connect", skp, okp->smk_known, + MAY_WRITE, rc); + if (rc == 0) { rc = smk_access(okp, okp->smk_known, MAY_WRITE, NULL); + rc = smk_bu_note("UDS connect", okp, okp->smk_known, + MAY_WRITE, rc); + } } /* @@ -3121,6 +3333,7 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) struct socket_smack *osp = other->sk->sk_security; struct smack_known *skp; struct smk_audit_info ad; + int rc; #ifdef CONFIG_AUDIT struct lsm_network_audit net; @@ -3133,7 +3346,10 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) return 0; skp = ssp->smk_out; - return smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad); + rc = smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad); + rc = smk_bu_note("UDS send", skp, osp->smk_in->smk_known, + MAY_WRITE, rc); + return rc; } /** @@ -3348,6 +3564,8 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) * for networking. */ rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad); + rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in->smk_known, + MAY_WRITE, rc); if (rc != 0) netlbl_skbuff_err(skb, rc, 0); break; @@ -3528,6 +3746,8 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, * here. Read access is not required. */ rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad); + rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in->smk_known, + MAY_WRITE, rc); if (rc != 0) return rc; @@ -3631,6 +3851,7 @@ static int smack_key_permission(key_ref_t key_ref, struct smk_audit_info ad; struct smack_known *tkp = smk_of_task(cred->security); int request = 0; + int rc; keyp = key_ref_to_ptr(key_ref); if (keyp == NULL) @@ -3655,7 +3876,9 @@ static int smack_key_permission(key_ref_t key_ref, request = MAY_READ; if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR)) request = MAY_WRITE; - return smk_access(tkp, keyp->security, request, &ad); + rc = smk_access(tkp, keyp->security, request, &ad); + rc = smk_bu_note("key access", tkp, keyp->security, request, rc); + return rc; } #endif /* CONFIG_KEYS */ diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 56a1439786a9..49a2248b525c 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -304,6 +304,10 @@ static int smk_perm_from_str(const char *string) case 'L': perm |= MAY_LOCK; break; + case 'b': + case 'B': + perm |= MAY_BRINGUP; + break; default: return perm; } @@ -616,6 +620,8 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) seq_putc(s, 't'); if (srp->smk_access & MAY_LOCK) seq_putc(s, 'l'); + if (srp->smk_access & MAY_BRINGUP) + seq_putc(s, 'b'); seq_putc(s, '\n'); } @@ -1880,7 +1886,10 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, else if (res != -ENOENT) return -EINVAL; - data[0] = res == 0 ? '1' : '0'; + /* + * smk_access() can return a value > 0 in the "bringup" case. + */ + data[0] = res >= 0 ? '1' : '0'; data[1] = '\0'; simple_transaction_set(file, 2); -- GitLab From 51dd2e8ec99cc83bd787f836f1d812f384a61dff Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 13 Aug 2014 14:01:21 +0200 Subject: [PATCH 0763/5088] gpio: zynq: Remove .owner field for driver There is no need to init .owner field. Based on the patch from Peter Griffin "mmc: remove .owner field for drivers using module_platform_driver" This patch removes the superflous .owner field for drivers which use the module_platform_driver API, as this is overriden in platform_driver_register anyway." Signed-off-by: Michal Simek Signed-off-by: Linus Walleij --- drivers/gpio/gpio-zynq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 31ad5df5dbc9..6e5146c8e254 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -688,7 +688,6 @@ MODULE_DEVICE_TABLE(of, zynq_gpio_of_match); static struct platform_driver zynq_gpio_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = &zynq_gpio_dev_pm_ops, .of_match_table = zynq_gpio_of_match, }, -- GitLab From a879891ee80413f6999905db43ad0d6852dfa6ca Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 14 Aug 2014 11:40:24 +0200 Subject: [PATCH 0764/5088] gpio: pxa: Documentation: provide example bindings for PXA3xx Add another example to describe bindings that work for PXA3xx boards. Signed-off-by: Daniel Mack Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/mrvl-gpio.txt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt index 66416261e14d..b2afdb27adeb 100644 --- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt @@ -19,7 +19,7 @@ Required properties: - gpio-controller : Marks the device node as a gpio controller. - #gpio-cells : Should be one. It is the pin number. -Example: +Example for a MMP platform: gpio: gpio@d4019000 { compatible = "marvell,mmp-gpio"; @@ -32,6 +32,19 @@ Example: #interrupt-cells = <1>; }; +Example for a PXA3xx platform: + + gpio: gpio@40e00000 { + compatible = "intel,pxa3xx-gpio"; + reg = <0x40e00000 0x10000>; + interrupt-names = "gpio0", "gpio1", "gpio_mux"; + interrupts = <8 9 10>; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x2>; + }; + * Marvell Orion GPIO Controller Required properties: -- GitLab From 5a2533a7478334593c50284fd414c70b3b9217c0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 18 Aug 2014 11:54:55 +0200 Subject: [PATCH 0765/5088] gpio: zynq: Reduce level of indention in zynq_gpio_irqhandler() zynq_gpio_irqhandler() uses up to 7 tabs of indention in some parts. Refactor things to use a helper function for the inner loop to reduce the indention to a sane level. Signed-off-by: Lars-Peter Clausen Signed-off-by: Linus Walleij --- drivers/gpio/gpio-zynq.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 6e5146c8e254..36034b6811bb 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -457,6 +457,24 @@ static struct irq_chip zynq_gpio_edge_irqchip = { .irq_set_wake = zynq_gpio_set_wake, }; +static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio, + unsigned int bank_num, + unsigned long pending) +{ + struct irq_domain *irqdomain = gpio->chip.irqdomain; + int offset; + + if (!pending) + return; + + for_each_set_bit(offset, &pending, 32) { + unsigned int gpio_irq; + + gpio_irq = irq_find_mapping(irqdomain, offset); + generic_handle_irq(gpio_irq); + } +} + /** * zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device * @irq: irq number of the gpio bank where interrupt has occurred @@ -482,18 +500,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); int_enb = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_INTMASK_OFFSET(bank_num)); - int_sts &= ~int_enb; - if (int_sts) { - int offset; - unsigned long pending = int_sts; - - for_each_set_bit(offset, &pending, 32) { - unsigned int gpio_irq = - irq_find_mapping(gpio->chip.irqdomain, - offset); - generic_handle_irq(gpio_irq); - } - } + zynq_gpio_handle_bank_irq(gpio, bank_num, int_sts & ~int_enb); } chained_irq_exit(irqchip, desc); -- GitLab From e46cf32ced90d00972d5c3d9322cdb848d183338 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 19 Aug 2014 10:06:08 -0700 Subject: [PATCH 0766/5088] gpio: acpi: normalize use of gpiochip_get_desc() GPIO descriptors are changing from unique and permanent tokens to allocated resources. Therefore gpiochip_get_desc() cannot be used as a way to obtain a global GPIO descriptor anymore. This patch updates the gpiolib ACPI support code to keep and use the descriptor returned by a centralized call to gpiochip_get_desc(). Signed-off-by: Alexandre Courbot Tested-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index d62eaaa75397..84540025aa08 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -25,10 +25,12 @@ struct acpi_gpio_event { acpi_handle handle; unsigned int pin; unsigned int irq; + struct gpio_desc *desc; }; struct acpi_gpio_connection { struct list_head node; + unsigned int pin; struct gpio_desc *desc; }; @@ -197,6 +199,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, event->handle = evt_handle; event->irq = irq; event->pin = pin; + event->desc = desc; ret = request_threaded_irq(event->irq, NULL, handler, irqflags, "ACPI:Event", event); @@ -280,7 +283,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) struct gpio_desc *desc; free_irq(event->irq, event); - desc = gpiochip_get_desc(chip, event->pin); + desc = event->desc; if (WARN_ON(IS_ERR(desc))) continue; gpio_unlock_as_irq(chip, event->pin); @@ -406,24 +409,26 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, struct gpio_desc *desc; bool found; - desc = gpiochip_get_desc(chip, pin); - if (IS_ERR(desc)) { - status = AE_ERROR; - goto out; - } - mutex_lock(&achip->conn_lock); found = false; list_for_each_entry(conn, &achip->conns, node) { - if (conn->desc == desc) { + if (conn->pin == pin) { found = true; + desc = conn->desc; break; } } if (!found) { int ret; + desc = gpiochip_get_desc(chip, pin); + if (IS_ERR(desc)) { + status = AE_ERROR; + mutex_unlock(&achip->conn_lock); + goto out; + } + ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion"); if (ret) { status = AE_ERROR; @@ -462,6 +467,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, goto out; } + conn->pin = pin; conn->desc = desc; list_add_tail(&conn->node, &achip->conns); } -- GitLab From abdc08a3a263a20e49534a36291d657bf53dda5b Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 19 Aug 2014 10:06:09 -0700 Subject: [PATCH 0767/5088] gpio: change gpiochip_request_own_desc() prototype The current prototype of gpiochip_request_own_desc() requires to obtain a pointer to a descriptor. This is in contradiction to all other GPIO request schemes, and imposes an extra step of obtaining a descriptor to drivers. Most drivers actually cannot even perform that step since the function that does it (gpichip_get_desc()) is gpiolib-private. Change gpiochip_request_own_desc() to return a descriptor from a (chip, hwnum) tuple and update users of this function (currently gpiolib-acpi only). Signed-off-by: Alexandre Courbot Tested-by: Mika Westerberg Signed-off-by: Linus Walleij --- Documentation/gpio/driver.txt | 3 ++- drivers/gpio/gpiolib-acpi.c | 20 +++----------------- drivers/gpio/gpiolib.c | 18 ++++++++++++++---- include/linux/gpio/driver.h | 3 ++- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt index 18790c237977..23b751a10d7b 100644 --- a/Documentation/gpio/driver.txt +++ b/Documentation/gpio/driver.txt @@ -178,7 +178,8 @@ does not help since it pins the module to the kernel forever (it calls try_module_get()). A GPIO driver can use the following functions instead to request and free descriptors without being pinned to the kernel forever. - int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) + struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc, + const char *label) void gpiochip_free_own_desc(struct gpio_desc *desc) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 84540025aa08..f9103e72e2a4 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -145,14 +145,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, if (!handler) return AE_BAD_PARAMETER; - desc = gpiochip_get_desc(chip, pin); + desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event"); if (IS_ERR(desc)) { - dev_err(chip->dev, "Failed to get GPIO descriptor\n"); - return AE_ERROR; - } - - ret = gpiochip_request_own_desc(desc, "ACPI:Event"); - if (ret) { dev_err(chip->dev, "Failed to request GPIO\n"); return AE_ERROR; } @@ -420,22 +414,14 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, } } if (!found) { - int ret; - - desc = gpiochip_get_desc(chip, pin); + desc = gpiochip_request_own_desc(chip, pin, + "ACPI:OpRegion"); if (IS_ERR(desc)) { status = AE_ERROR; mutex_unlock(&achip->conn_lock); goto out; } - ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion"); - if (ret) { - status = AE_ERROR; - mutex_unlock(&achip->conn_lock); - goto out; - } - switch (agpio->io_restriction) { case ACPI_IO_RESTRICT_INPUT: gpiod_direction_input(desc); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 15cc0bb65dda..a5831d6a9b91 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -895,12 +895,22 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); * allows the GPIO chip module to be unloaded as needed (we assume that the * GPIO chip driver handles freeing the GPIOs it has requested). */ -int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) +struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, + const char *label) { - if (!desc || !desc->chip) - return -EINVAL; + struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum); + int err; + + if (IS_ERR(desc)) { + chip_err(chip, "failed to get GPIO descriptor\n"); + return desc; + } + + err = __gpiod_request(desc, label); + if (err < 0) + return ERR_PTR(err); - return __gpiod_request(desc, label); + return desc; } EXPORT_SYMBOL_GPL(gpiochip_request_own_desc); diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index e78a2373e374..a2de58fffd19 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -166,7 +166,8 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, #endif /* CONFIG_GPIO_IRQCHIP */ -int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label); +struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, + const char *label); void gpiochip_free_own_desc(struct gpio_desc *desc); #else /* CONFIG_GPIOLIB */ -- GitLab From f9bda39d1384f1ecae131fd283db27a01b5fb6cd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:09:14 +0900 Subject: [PATCH 0768/5088] backlight: adp5520: Add blank line after declarations Fixed the following checkpatch warning. WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/adp5520_bl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index b56cb3f77174..dd88ba1d71ce 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -67,6 +67,7 @@ static int adp5520_bl_set(struct backlight_device *bl, int brightness) static int adp5520_bl_update_status(struct backlight_device *bl) { int brightness = bl->props.brightness; + if (bl->props.power != FB_BLANK_UNBLANK) brightness = 0; -- GitLab From 5e548f0f55a9f8165a3f36226ac5d3f42a05cf47 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:09:52 +0900 Subject: [PATCH 0769/5088] backlight: adp8860: Add blank line after declarations Fixed the following checkpatch warning. WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/adp8860_bl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index be8d83deca7d..71147f4461b8 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -181,6 +181,7 @@ static int adp8860_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask static void adp8860_led_work(struct work_struct *work) { struct adp8860_led *led = container_of(work, struct adp8860_led, work); + adp8860_write(led->client, ADP8860_ISC1 - led->id + 1, led->new_brightness >> 1); } @@ -362,6 +363,7 @@ static int adp8860_bl_set(struct backlight_device *bl, int brightness) static int adp8860_bl_update_status(struct backlight_device *bl) { int brightness = bl->props.brightness; + if (bl->props.power != FB_BLANK_UNBLANK) brightness = 0; @@ -499,6 +501,7 @@ static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev, { struct adp8860_bl *data = dev_get_drvdata(dev); int ret = kstrtoul(buf, 10, &data->cached_daylight_max); + if (ret) return ret; -- GitLab From fe9a86235dd6367ea6748bc4f9e03fe1f7a15614 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:10:11 +0900 Subject: [PATCH 0770/5088] backlight: adp8870: Add blank line after declarations Fixed the following checkpatch warning. WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/adp8870_bl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 251af4d38d86..037e43083343 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -144,6 +144,7 @@ static int adp8870_read(struct i2c_client *client, int reg, uint8_t *val) static int adp8870_write(struct i2c_client *client, u8 reg, u8 val) { int ret = i2c_smbus_write_byte_data(client, reg, val); + if (ret) dev_err(&client->dev, "failed to write\n"); @@ -195,6 +196,7 @@ static int adp8870_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask static void adp8870_led_work(struct work_struct *work) { struct adp8870_led *led = container_of(work, struct adp8870_led, work); + adp8870_write(led->client, ADP8870_ISC1 + led->id - 1, led->new_brightness >> 1); } @@ -399,6 +401,7 @@ static int adp8870_bl_set(struct backlight_device *bl, int brightness) static int adp8870_bl_update_status(struct backlight_device *bl) { int brightness = bl->props.brightness; + if (bl->props.power != FB_BLANK_UNBLANK) brightness = 0; @@ -649,6 +652,7 @@ static ssize_t adp8870_bl_l1_daylight_max_store(struct device *dev, { struct adp8870_bl *data = dev_get_drvdata(dev); int ret = kstrtoul(buf, 10, &data->cached_daylight_max); + if (ret) return ret; -- GitLab From 5b0d6e1912fce778b7a759e54676d492ad359934 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:10:34 +0900 Subject: [PATCH 0771/5088] backlight: ams369fg06: Remove 'else' after a return Fixed the following checkpatch warning. WARNING: else is not generally useful after a break or return Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/ams369fg06.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c index 4726c8be626f..5f897f99cc9b 100644 --- a/drivers/video/backlight/ams369fg06.c +++ b/drivers/video/backlight/ams369fg06.c @@ -325,11 +325,11 @@ static int ams369fg06_power_on(struct ams369fg06 *lcd) if (!pd->reset) { dev_err(lcd->dev, "reset is NULL.\n"); return -EINVAL; - } else { - pd->reset(lcd->ld); - msleep(pd->reset_delay); } + pd->reset(lcd->ld); + msleep(pd->reset_delay); + ret = ams369fg06_ldi_init(lcd); if (ret) { dev_err(lcd->dev, "failed to initialize ldi.\n"); -- GitLab From ff32c2fa811674855dab0881417674404d25ebab Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:10:55 +0900 Subject: [PATCH 0772/5088] backlight: corgi_lcd: Add blank line after declarations Fixed the following checkpatch warning. WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/corgi_lcd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index 51d18d637e2b..d7c37a8ccd1f 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -143,6 +143,7 @@ static void lcdtg_i2c_send_byte(struct corgi_lcd *lcd, uint8_t base, uint8_t data) { int i; + for (i = 0; i < 8; i++) { if (data & 0x80) lcdtg_i2c_send_bit(lcd, base | POWER0_COM_DOUT); -- GitLab From 7beeee469a2e8baece57ad5552e18671b7e56a30 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:11:14 +0900 Subject: [PATCH 0773/5088] backlight: cr_bllcd: Add blank line after declarations Fixed the following checkpatch warning. WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/cr_bllcd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index f3fed9ef745f..3e3880fc8c8e 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -235,6 +235,7 @@ static int cr_backlight_probe(struct platform_device *pdev) static int cr_backlight_remove(struct platform_device *pdev) { struct cr_panel *crp = platform_get_drvdata(pdev); + crp->cr_backlight_device->props.power = FB_BLANK_POWERDOWN; crp->cr_backlight_device->props.brightness = 0; crp->cr_backlight_device->props.max_brightness = 0; -- GitLab From 547f60cee1b604477fde1cbc1bb2da8f6853c9bd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:11:33 +0900 Subject: [PATCH 0774/5088] backlight: ili922x: Remove 'else' after a return Fixed the following checkpatch warning. WARNING: else is not generally useful after a break or return Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/ili922x.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/video/backlight/ili922x.c b/drivers/video/backlight/ili922x.c index ea67fe199e34..e7f0890cc211 100644 --- a/drivers/video/backlight/ili922x.c +++ b/drivers/video/backlight/ili922x.c @@ -495,17 +495,18 @@ static int ili922x_probe(struct spi_device *spi) "no LCD found: Chip ID 0x%x, ret %d\n", reg, ret); return -ENODEV; - } else { - dev_info(&spi->dev, "ILI%x found, SPI freq %d, mode %d\n", - reg, spi->max_speed_hz, spi->mode); } + dev_info(&spi->dev, "ILI%x found, SPI freq %d, mode %d\n", + reg, spi->max_speed_hz, spi->mode); + ret = ili922x_read_status(spi, ®); if (ret) { dev_err(&spi->dev, "reading RS failed...\n"); return ret; - } else - dev_dbg(&spi->dev, "status: 0x%x\n", reg); + } + + dev_dbg(&spi->dev, "status: 0x%x\n", reg); ili922x_display_init(spi); -- GitLab From e09bceac75b86c672b6e41b9341fa50325713438 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:11:52 +0900 Subject: [PATCH 0775/5088] backlight: ld9040: Remove 'else' after a return Fixed the following checkpatch warning. WARNING: else is not generally useful after a break or return Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/ld9040.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c index ccb44e8e4927..f71eaf10c4eb 100644 --- a/drivers/video/backlight/ld9040.c +++ b/drivers/video/backlight/ld9040.c @@ -566,11 +566,11 @@ static int ld9040_power_on(struct ld9040 *lcd) if (!pd->reset) { dev_err(lcd->dev, "reset is NULL.\n"); return -EINVAL; - } else { - pd->reset(lcd->ld); - msleep(pd->reset_delay); } + pd->reset(lcd->ld); + msleep(pd->reset_delay); + ret = ld9040_ldi_init(lcd); if (ret) { dev_err(lcd->dev, "failed to initialize ldi.\n"); -- GitLab From 3033d2c0dd1d7ecbc8d4e04a7c1085931f86b68a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:12:14 +0900 Subject: [PATCH 0776/5088] backlight: lm3639: Remove unnecessary return statements Fixed the following checkpatch warning. WARNING: void function return statements are not generally useful Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/lm3639_bl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c index 5f36808d214f..cd50df5807ea 100644 --- a/drivers/video/backlight/lm3639_bl.c +++ b/drivers/video/backlight/lm3639_bl.c @@ -254,7 +254,6 @@ static void lm3639_torch_brightness_set(struct led_classdev *cdev, return; out: dev_err(pchip->dev, "i2c failed to access register\n"); - return; } /* flash */ @@ -293,7 +292,6 @@ static void lm3639_flash_brightness_set(struct led_classdev *cdev, return; out: dev_err(pchip->dev, "i2c failed to access register\n"); - return; } static const struct regmap_config lm3639_regmap = { -- GitLab From b50ffb8a5f7f7dedd92a3bc2733605b3888fae8c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:12:37 +0900 Subject: [PATCH 0777/5088] backlight: lms501kf03: Remove 'else' after a return Fixed the following checkpatch warning. WARNING: else is not generally useful after a break or return Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/lms501kf03.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/lms501kf03.c b/drivers/video/backlight/lms501kf03.c index 77258b7b04be..7e3810308c3e 100644 --- a/drivers/video/backlight/lms501kf03.c +++ b/drivers/video/backlight/lms501kf03.c @@ -232,19 +232,19 @@ static int lms501kf03_power_on(struct lms501kf03 *lcd) if (!pd->power_on) { dev_err(lcd->dev, "power_on is NULL.\n"); return -EINVAL; - } else { - pd->power_on(lcd->ld, 1); - msleep(pd->power_on_delay); } + pd->power_on(lcd->ld, 1); + msleep(pd->power_on_delay); + if (!pd->reset) { dev_err(lcd->dev, "reset is NULL.\n"); return -EINVAL; - } else { - pd->reset(lcd->ld); - msleep(pd->reset_delay); } + pd->reset(lcd->ld); + msleep(pd->reset_delay); + ret = lms501kf03_ldi_init(lcd); if (ret) { dev_err(lcd->dev, "failed to initialize ldi.\n"); -- GitLab From a94cb126048058980ff57f6a7fa5e8237b8f6b44 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:12:53 +0900 Subject: [PATCH 0778/5088] backlight: lp855x: Add blank line after declarations Fixed the following checkpatch warning. WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/lp855x_bl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index dcdd5443efcf..25fb8e3d75b1 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -268,6 +268,7 @@ static int lp855x_bl_update_status(struct backlight_device *bl) } else if (lp->mode == REGISTER_BASED) { u8 val = bl->props.brightness; + lp855x_write_byte(lp, lp->cfg->reg_brightness, val); } @@ -308,6 +309,7 @@ static ssize_t lp855x_get_chip_id(struct device *dev, struct device_attribute *attr, char *buf) { struct lp855x *lp = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname); } -- GitLab From c915ae50d60df9d3e869ca05ea0f3dc8614a9bf9 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:13:10 +0900 Subject: [PATCH 0779/5088] backlight: pcf50633: Add blank line after declarations Fixed the following checkpatch warning. WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/pcf50633-backlight.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c index b95d3b0aaffe..85bd573b6d15 100644 --- a/drivers/video/backlight/pcf50633-backlight.c +++ b/drivers/video/backlight/pcf50633-backlight.c @@ -90,6 +90,7 @@ static int pcf50633_bl_update_status(struct backlight_device *bl) static int pcf50633_bl_get_brightness(struct backlight_device *bl) { struct pcf50633_bl *pcf_bl = bl_get_data(bl); + return pcf_bl->brightness; } -- GitLab From 3bf3b79fab16b97b0a5a1232af760e8d7a2d3a78 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:13:30 +0900 Subject: [PATCH 0780/5088] backlight: s6e63m0: Remove 'else' after a return Fixed the following checkpatch warning. WARNING: else is not generally useful after a break or return Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/s6e63m0.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index f3a65c8940ed..28bfa127fee4 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c @@ -507,19 +507,19 @@ static int s6e63m0_power_on(struct s6e63m0 *lcd) if (!pd->power_on) { dev_err(lcd->dev, "power_on is NULL.\n"); return -EINVAL; - } else { - pd->power_on(lcd->ld, 1); - msleep(pd->power_on_delay); } + pd->power_on(lcd->ld, 1); + msleep(pd->power_on_delay); + if (!pd->reset) { dev_err(lcd->dev, "reset is NULL.\n"); return -EINVAL; - } else { - pd->reset(lcd->ld); - msleep(pd->reset_delay); } + pd->reset(lcd->ld); + msleep(pd->reset_delay); + ret = s6e63m0_ldi_init(lcd); if (ret) { dev_err(lcd->dev, "failed to initialize ldi.\n"); -- GitLab From 51ed5dc253b4a11047266345d6ee30d0939f310e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:13:49 +0900 Subject: [PATCH 0781/5088] backlight: tdo24m: Add blank line after declarations Fixed the following checkpatch warning. WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/tdo24m.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index 908016fc5829..30afce33ef2a 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -300,12 +300,14 @@ static int tdo24m_power(struct tdo24m *lcd, int power) static int tdo24m_set_power(struct lcd_device *ld, int power) { struct tdo24m *lcd = lcd_get_data(ld); + return tdo24m_power(lcd, power); } static int tdo24m_get_power(struct lcd_device *ld) { struct tdo24m *lcd = lcd_get_data(ld); + return lcd->power; } -- GitLab From 4876b66497ed31fc10e235a34faa80c2de6adace Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:14:06 +0900 Subject: [PATCH 0782/5088] backlight: wm831x_bl: Add blank line after declarations Fixed the following checkpatch warning. WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/wm831x_bl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 6f596161916d..6eab0d6c262a 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -111,6 +111,7 @@ static int wm831x_backlight_update_status(struct backlight_device *bl) static int wm831x_backlight_get_brightness(struct backlight_device *bl) { struct wm831x_backlight_data *data = bl_get_data(bl); + return data->current_brightness; } -- GitLab From 5b007dfee8a8a9eac95a866b1dd151e136f47aa8 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:14:25 +0900 Subject: [PATCH 0783/5088] backlight: jornada720: Remove 'else' after a return Fixed the following checkpatch warning. WARNING: else is not generally useful after a break or return Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/jornada720_bl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c index 6ce96b4a8796..7e6ff5346892 100644 --- a/drivers/video/backlight/jornada720_bl.c +++ b/drivers/video/backlight/jornada720_bl.c @@ -41,11 +41,11 @@ static int jornada_bl_get_brightness(struct backlight_device *bd) dev_err(&bd->dev, "get brightness timeout\n"); jornada_ssp_end(); return -ETIMEDOUT; - } else { - /* exchange txdummy for value */ - ret = jornada_ssp_byte(TXDUMMY); } + /* exchange txdummy for value */ + ret = jornada_ssp_byte(TXDUMMY); + jornada_ssp_end(); return BL_MAX_BRIGHT - ret; -- GitLab From 3e51cd93f534b475c065c1513734860ce28a8da3 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:14:43 +0900 Subject: [PATCH 0784/5088] backlight: jornada720: Remove 'else' after a return Fixed the following checkpatch warning. WARNING: else is not generally useful after a break or return Suggested-by: Lee Jones Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/jornada720_lcd.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/video/backlight/jornada720_lcd.c b/drivers/video/backlight/jornada720_lcd.c index 228bc319de19..dfa0fa0d5c78 100644 --- a/drivers/video/backlight/jornada720_lcd.c +++ b/drivers/video/backlight/jornada720_lcd.c @@ -27,11 +27,7 @@ static int jornada_lcd_get_power(struct lcd_device *ld) { - /* LDD2 in PPC = LCD POWER */ - if (PPSR & PPC_LDD2) - return FB_BLANK_UNBLANK; /* PW ON */ - else - return FB_BLANK_POWERDOWN; /* PW OFF */ + return PPSR & PPC_LDD2 ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; } static int jornada_lcd_get_contrast(struct lcd_device *ld) -- GitLab From b6af73b42219aa6b253ef5c0020eff1019485ffc Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 27 Aug 2014 10:15:01 +0900 Subject: [PATCH 0785/5088] backlight: omap1: add blank line after declarations Fixed the following checkpatch warning. WARNING: Missing a blank line after declarations Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/omap1_bl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index a0dcd88ac74f..546d94df21d5 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -120,6 +120,7 @@ static int omapbl_update_status(struct backlight_device *dev) static int omapbl_get_intensity(struct backlight_device *dev) { struct omap_backlight *bl = bl_get_data(dev); + return bl->current_intensity; } -- GitLab From 2d82eeb02655e32358efd42598d8276284c23364 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 27 Aug 2014 20:07:46 -0700 Subject: [PATCH 0786/5088] ASoC: simple-card: use asoc_simple_xxx prefix simple-card driver is using asoc_simple_xxx() prefix. simple_card_dai_link_of() should be asoc_simple_card_dai_link_of(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 21b0ea24bc1d..c5445b0ae9ff 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -163,11 +163,11 @@ asoc_simple_card_sub_parse_of(struct device_node *np, return 0; } -static int simple_card_dai_link_of(struct device_node *node, - struct device *dev, - struct snd_soc_dai_link *dai_link, - struct simple_dai_props *dai_props, - bool is_top_level_node) +static int asoc_simple_card_dai_link_of(struct device_node *node, + struct device *dev, + struct snd_soc_dai_link *dai_link, + struct simple_dai_props *dai_props, + bool is_top_level_node) { struct device_node *np = NULL; struct device_node *bitclkmaster = NULL; @@ -337,16 +337,18 @@ static int asoc_simple_card_parse_of(struct device_node *node, int i; for (i = 0; (np = of_get_next_child(node, np)); i++) { dev_dbg(dev, "\tlink %d:\n", i); - ret = simple_card_dai_link_of(np, dev, dai_link + i, - dai_props + i, false); + ret = asoc_simple_card_dai_link_of(np, dev, + dai_link + i, + dai_props + i, + false); if (ret < 0) { of_node_put(np); return ret; } } } else { - ret = simple_card_dai_link_of(node, dev, dai_link, dai_props, - true); + ret = asoc_simple_card_dai_link_of(node, dev, + dai_link, dai_props, true); if (ret < 0) return ret; } -- GitLab From 179949bc04c7157a4b2279f62a842638b61f78f9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 27 Aug 2014 20:08:06 -0700 Subject: [PATCH 0787/5088] ASoC: simple-card: remove dai_link->cpu_dai_name when DT f687d900d30a61dda38db2a99239f5284a86a309 (ASoC: simple-card: cpu_dai_name creates confusion when DT case) removed dai_link->cpu_dai_name when DT case, since it uses DT phand in soc_bind_dai_link(). This binding will fail if it has cpu_dai_name. 6a91a17bd7b92b2d2aa9ece85457f52a62fd7708 (ASoC: simple-card: Handle many DAI links) added multi DAI link support to simple-card driver. Then, removing cpu_dai_name was cared only single DAI. But, it is needed in all DT cases. This patch moves it to asoc_simple_card_dai_link_of() so that care about all DAIs. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index c5445b0ae9ff..e8185a0b933f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -285,6 +285,17 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, dai_props->codec_dai.fmt, dai_props->codec_dai.sysclk); + /* + * soc_bind_dai_link() will check cpu name + * after of_node matching if dai_link has cpu_dai_name. + * but, it will never match if name was created by fmt_single_name() + * remove cpu_dai_name to escape name matching. + * see + * fmt_single_name() + * fmt_multiple_name() + */ + dai_link->cpu_dai_name = NULL; + dai_link_of_err: if (np) of_node_put(np); @@ -429,18 +440,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev) goto err; } - /* - * soc_bind_dai_link() will check cpu name - * after of_node matching if dai_link has cpu_dai_name. - * but, it will never match if name was created by fmt_single_name() - * remove cpu_dai_name to escape name matching. - * see - * fmt_single_name() - * fmt_multiple_name() - */ - if (num_links == 1) - dai_link->cpu_dai_name = NULL; - } else { struct asoc_simple_card_info *cinfo; -- GitLab From a5960bd5984c808cdf7aa528e162e9e20e61b923 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 27 Aug 2014 20:08:27 -0700 Subject: [PATCH 0788/5088] ASoC: simple-card: dai_link->init should be cared when multi DAI 6a91a17bd7b92b2d2aa9ece85457f52a62fd7708 (ASoC: simple-card: Handle many DAI links) added multi DAI support on simple-card. This means priv->dai_link might be pointer of multi DAI. dai_link->init is needed for all DAI. This patch cares it for all DAIs on DT/non-DT Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index e8185a0b933f..89027047364f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -274,6 +274,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, dai_link->codec_dai_name); dai_link->name = dai_link->stream_name = name; dai_link->ops = &asoc_simple_card_ops; + dai_link->init = asoc_simple_card_dai_init; dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); dev_dbg(dev, "\tcpu : %s / %04x / %d\n", @@ -465,6 +466,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) dai_link->codec_name = cinfo->codec; dai_link->cpu_dai_name = cinfo->cpu_dai.name; dai_link->codec_dai_name = cinfo->codec_dai.name; + dai_link->init = asoc_simple_card_dai_init; memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, sizeof(priv->dai_props->cpu_dai)); memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, @@ -474,11 +476,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev) priv->dai_props->codec_dai.fmt |= cinfo->daifmt; } - /* - * init snd_soc_dai_link - */ - dai_link->init = asoc_simple_card_dai_init; - snd_soc_card_set_drvdata(&priv->snd_card, priv); ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); -- GitLab From a44a750e5299fe2ece5aa68e8562dd6e2c2b16f4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 27 Aug 2014 20:08:47 -0700 Subject: [PATCH 0789/5088] ASoC: simple-card: use common for_each_child_of_node() for loop Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 89027047364f..fd8b04588948 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -346,8 +346,9 @@ static int asoc_simple_card_parse_of(struct device_node *node, if (multi) { struct device_node *np = NULL; - int i; - for (i = 0; (np = of_get_next_child(node, np)); i++) { + int i = 0; + + for_each_child_of_node(node, np) { dev_dbg(dev, "\tlink %d:\n", i); ret = asoc_simple_card_dai_link_of(np, dev, dai_link + i, @@ -357,6 +358,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, of_node_put(np); return ret; } + i++; } } else { ret = asoc_simple_card_dai_link_of(node, dev, -- GitLab From 55872c5a3c01f0fe7b5298d19e24e237f5b5ff06 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 28 Aug 2014 15:05:40 -0600 Subject: [PATCH 0790/5088] bsg: fix potential error pointer dereference Dan writes: block/bsg.c:327 bsg_map_hdr() error: 'next_rq' dereferencing possible ERR_PTR(). Fix this by setting next_rq to NULL, for the case where it can be != NULL but an error pointer. Reported-by: Dan Carpenter Signed-off-by: Jens Axboe --- block/bsg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/bsg.c b/block/bsg.c index 73c78fd12cc1..276e869e686c 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -287,6 +287,7 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm, next_rq = blk_get_request(q, READ, GFP_KERNEL); if (IS_ERR(next_rq)) { ret = PTR_ERR(next_rq); + next_rq = NULL; goto out; } rq->next_rq = next_rq; -- GitLab From e95ef49b7f8f497bdb529f4cb1fe228e986b3255 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Fri, 29 Aug 2014 17:02:53 +0200 Subject: [PATCH 0791/5088] Small fixes in comments describing function parameters Signed-off-by: Lukasz Pawelczyk --- security/smack/smack_lsm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 154548ea7d87..478d99e0a0eb 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -771,8 +771,8 @@ static void smack_inode_free_security(struct inode *inode) /** * smack_inode_init_security - copy out the smack from an inode - * @inode: the inode - * @dir: unused + * @inode: the newly created inode + * @dir: containing directory object * @qstr: unused * @name: where to put the attribute name * @value: where to put the attribute value @@ -923,10 +923,10 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) /** * smack_inode_rename - Smack check on rename - * @old_inode: the old directory - * @old_dentry: unused - * @new_inode: the new directory - * @new_dentry: unused + * @old_inode: unused + * @old_dentry: the old object + * @new_inode: unused + * @new_dentry: the new object * * Read and write access is required on both the old and * new directories. @@ -1017,7 +1017,7 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) /** * smack_inode_getattr - Smack check for getting attributes - * @mnt: unused + * @mnt: vfsmount of the object * @dentry: the object * * Returns 0 if access is permitted, an error code otherwise @@ -1042,8 +1042,8 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) * smack_inode_setxattr - Smack check for setting xattrs * @dentry: the object * @name: name of the attribute - * @value: unused - * @size: unused + * @value: value of the attribute + * @size: size of the value * @flags: unused * * This protects the Smack attribute explicitly. -- GitLab From d01757904d9deb619e23c9450218829943a46822 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Fri, 29 Aug 2014 17:02:54 +0200 Subject: [PATCH 0792/5088] Fix a bidirectional UDS connect check typo The 54e70ec5eb090193b03e69d551fa6771a5a217c4 commit introduced a bidirectional check that should have checked for mutual WRITE access between two labels. Due to a typo the second check was incorrect. Signed-off-by: Lukasz Pawelczyk --- security/smack/smack_lsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 478d99e0a0eb..00443a9039b8 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3302,8 +3302,8 @@ static int smack_unix_stream_connect(struct sock *sock, rc = smk_bu_note("UDS connect", skp, okp->smk_known, MAY_WRITE, rc); if (rc == 0) { - rc = smk_access(okp, okp->smk_known, MAY_WRITE, NULL); - rc = smk_bu_note("UDS connect", okp, okp->smk_known, + rc = smk_access(okp, skp->smk_known, MAY_WRITE, NULL); + rc = smk_bu_note("UDS connect", okp, skp->smk_known, MAY_WRITE, rc); } } -- GitLab From 21c7eae21a2100a89cfb8cebaf7b770271f32c6e Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Fri, 29 Aug 2014 17:02:55 +0200 Subject: [PATCH 0793/5088] Make Smack operate on smack_known struct where it still used char* Smack used to use a mix of smack_known struct and char* throughout its APIs and implementation. This patch unifies the behaviour and makes it store and operate exclusively on smack_known struct pointers when managing labels. Signed-off-by: Lukasz Pawelczyk Conflicts: security/smack/smack_access.c security/smack/smack_lsm.c --- security/smack/smack.h | 34 ++-- security/smack/smack_access.c | 94 ++++------- security/smack/smack_lsm.c | 299 +++++++++++++++++----------------- security/smack/smackfs.c | 61 +++---- 4 files changed, 233 insertions(+), 255 deletions(-) diff --git a/security/smack/smack.h b/security/smack/smack.h index 2d13d5fb17ed..b828a379377c 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -71,11 +71,11 @@ struct smack_known { #define SMK_CIPSOLEN 24 struct superblock_smack { - char *smk_root; - char *smk_floor; - char *smk_hat; - char *smk_default; - int smk_initialized; + struct smack_known *smk_root; + struct smack_known *smk_floor; + struct smack_known *smk_hat; + struct smack_known *smk_default; + int smk_initialized; }; struct socket_smack { @@ -88,7 +88,7 @@ struct socket_smack { * Inode smack data */ struct inode_smack { - char *smk_inode; /* label of the fso */ + struct smack_known *smk_inode; /* label of the fso */ struct smack_known *smk_task; /* label of the task */ struct smack_known *smk_mmap; /* label of the mmap domain */ struct mutex smk_lock; /* initialization lock */ @@ -112,7 +112,7 @@ struct task_smack { struct smack_rule { struct list_head list; struct smack_known *smk_subject; - char *smk_object; + struct smack_known *smk_object; int smk_access; }; @@ -123,7 +123,7 @@ struct smk_netlbladdr { struct list_head list; struct sockaddr_in smk_host; /* network address */ struct in_addr smk_mask; /* network mask */ - char *smk_label; /* label */ + struct smack_known *smk_label; /* label */ }; /* @@ -227,23 +227,23 @@ struct smk_audit_info { /* * These functions are in smack_lsm.c */ -struct inode_smack *new_inode_smack(char *); +struct inode_smack *new_inode_smack(struct smack_known *); /* * These functions are in smack_access.c */ int smk_access_entry(char *, char *, struct list_head *); -int smk_access(struct smack_known *, char *, int, struct smk_audit_info *); -int smk_tskacc(struct task_smack *, char *, u32, struct smk_audit_info *); -int smk_curacc(char *, u32, struct smk_audit_info *); +int smk_access(struct smack_known *, struct smack_known *, + int, struct smk_audit_info *); +int smk_tskacc(struct task_smack *, struct smack_known *, + u32, struct smk_audit_info *); +int smk_curacc(struct smack_known *, u32, struct smk_audit_info *); struct smack_known *smack_from_secid(const u32); char *smk_parse_smack(const char *string, int len); int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); -char *smk_import(const char *, int); struct smack_known *smk_import_entry(const char *, int); void smk_insert_entry(struct smack_known *skp); struct smack_known *smk_find_entry(const char *); -u32 smack_to_secid(const char *); /* * Shared data. @@ -253,7 +253,7 @@ extern int smack_cipso_mapped; extern struct smack_known *smack_net_ambient; extern struct smack_known *smack_onlycap; extern struct smack_known *smack_syslog_label; -extern const char *smack_cipso_option; +extern struct smack_known smack_cipso_option; extern int smack_ptrace_rule; extern struct smack_known smack_known_floor; @@ -282,9 +282,9 @@ static inline int smk_inode_transmutable(const struct inode *isp) } /* - * Present a pointer to the smack label in an inode blob. + * Present a pointer to the smack label entry in an inode blob. */ -static inline char *smk_of_inode(const struct inode *isp) +static inline struct smack_known *smk_of_inode(const struct inode *isp) { struct inode_smack *sip = isp->i_security; return sip->smk_inode; diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 9f02cb0ac85e..5b970ffde024 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -94,7 +94,7 @@ int smk_access_entry(char *subject_label, char *object_label, struct smack_rule *srp; list_for_each_entry_rcu(srp, rule_list, list) { - if (srp->smk_object == object_label && + if (srp->smk_object->smk_known == object_label && srp->smk_subject->smk_known == subject_label) { may = srp->smk_access; break; @@ -111,8 +111,8 @@ int smk_access_entry(char *subject_label, char *object_label, /** * smk_access - determine if a subject has a specific access to an object - * @subject_known: a pointer to the subject's Smack label entry - * @object_label: a pointer to the object's Smack label + * @subject: a pointer to the subject's Smack label entry + * @object: a pointer to the object's Smack label entry * @request: the access requested, in "MAY" format * @a : a pointer to the audit data * @@ -122,8 +122,8 @@ int smk_access_entry(char *subject_label, char *object_label, * * Smack labels are shared on smack_list */ -int smk_access(struct smack_known *subject_known, char *object_label, - int request, struct smk_audit_info *a) +int smk_access(struct smack_known *subject, struct smack_known *object, + int request, struct smk_audit_info *a) { int may = MAY_NOT; int rc = 0; @@ -133,7 +133,7 @@ int smk_access(struct smack_known *subject_known, char *object_label, * * A star subject can't access any object. */ - if (subject_known == &smack_known_star) { + if (subject == &smack_known_star) { rc = -EACCES; goto out_audit; } @@ -142,28 +142,28 @@ int smk_access(struct smack_known *subject_known, char *object_label, * Tasks cannot be assigned the internet label. * An internet subject can access any object. */ - if (object_label == smack_known_web.smk_known || - subject_known == &smack_known_web) + if (object == &smack_known_web || + subject == &smack_known_web) goto out_audit; /* * A star object can be accessed by any subject. */ - if (object_label == smack_known_star.smk_known) + if (object == &smack_known_star) goto out_audit; /* * An object can be accessed in any way by a subject * with the same label. */ - if (subject_known->smk_known == object_label) + if (subject->smk_known == object->smk_known) goto out_audit; /* * A hat subject can read any object. * A floor object can be read by any subject. */ if ((request & MAY_ANYREAD) == request) { - if (object_label == smack_known_floor.smk_known) + if (object == &smack_known_floor) goto out_audit; - if (subject_known == &smack_known_hat) + if (subject == &smack_known_hat) goto out_audit; } /* @@ -174,8 +174,8 @@ int smk_access(struct smack_known *subject_known, char *object_label, * indicates there is no entry for this pair. */ rcu_read_lock(); - may = smk_access_entry(subject_known->smk_known, object_label, - &subject_known->smk_rules); + may = smk_access_entry(subject->smk_known, object->smk_known, + &subject->smk_rules); rcu_read_unlock(); if (may <= 0 || (request & may) != request) { @@ -195,8 +195,8 @@ int smk_access(struct smack_known *subject_known, char *object_label, out_audit: #ifdef CONFIG_AUDIT if (a) - smack_log(subject_known->smk_known, object_label, request, - rc, a); + smack_log(subject->smk_known, object->smk_known, + request, rc, a); #endif return rc; @@ -204,8 +204,8 @@ int smk_access(struct smack_known *subject_known, char *object_label, /** * smk_tskacc - determine if a task has a specific access to an object - * @tsp: a pointer to the subject task - * @obj_label: a pointer to the object's Smack label + * @tsp: a pointer to the subject's task + * @obj_known: a pointer to the object's label entry * @mode: the access requested, in "MAY" format * @a : common audit data * @@ -214,24 +214,25 @@ int smk_access(struct smack_known *subject_known, char *object_label, * non zero otherwise. It allows that the task may have the capability * to override the rules. */ -int smk_tskacc(struct task_smack *subject, char *obj_label, +int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known, u32 mode, struct smk_audit_info *a) { - struct smack_known *skp = smk_of_task(subject); + struct smack_known *sbj_known = smk_of_task(tsp); int may; int rc; /* * Check the global rule list */ - rc = smk_access(skp, obj_label, mode, NULL); + rc = smk_access(sbj_known, obj_known, mode, NULL); if (rc >= 0) { /* * If there is an entry in the task's rule list * it can further restrict access. */ - may = smk_access_entry(skp->smk_known, obj_label, - &subject->smk_rules); + may = smk_access_entry(sbj_known->smk_known, + obj_known->smk_known, + &tsp->smk_rules); if (may < 0) goto out_audit; if ((mode & may) == mode) @@ -248,14 +249,15 @@ int smk_tskacc(struct task_smack *subject, char *obj_label, out_audit: #ifdef CONFIG_AUDIT if (a) - smack_log(skp->smk_known, obj_label, mode, rc, a); + smack_log(sbj_known->smk_known, obj_known->smk_known, + mode, rc, a); #endif return rc; } /** * smk_curacc - determine if current has a specific access to an object - * @obj_label: a pointer to the object's Smack label + * @obj_known: a pointer to the object's Smack label entry * @mode: the access requested, in "MAY" format * @a : common audit data * @@ -264,11 +266,12 @@ int smk_tskacc(struct task_smack *subject, char *obj_label, * non zero otherwise. It allows that current may have the capability * to override the rules. */ -int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) +int smk_curacc(struct smack_known *obj_known, + u32 mode, struct smk_audit_info *a) { struct task_smack *tsp = current_security(); - return smk_tskacc(tsp, obj_label, mode, a); + return smk_tskacc(tsp, obj_known, mode, a); } #ifdef CONFIG_AUDIT @@ -561,27 +564,6 @@ struct smack_known *smk_import_entry(const char *string, int len) return skp; } -/** - * smk_import - import a smack label - * @string: a text string that might be a Smack label - * @len: the maximum size, or zero if it is NULL terminated. - * - * Returns a pointer to the label in the label list that - * matches the passed string, adding it if necessary. - */ -char *smk_import(const char *string, int len) -{ - struct smack_known *skp; - - /* labels cannot begin with a '-' */ - if (string[0] == '-') - return NULL; - skp = smk_import_entry(string, len); - if (skp == NULL) - return NULL; - return skp->smk_known; -} - /** * smack_from_secid - find the Smack label associated with a secid * @secid: an integer that might be associated with a Smack label @@ -608,19 +590,3 @@ struct smack_known *smack_from_secid(const u32 secid) rcu_read_unlock(); return &smack_known_invalid; } - -/** - * smack_to_secid - find the secid associated with a Smack label - * @smack: the Smack label - * - * Returns the appropriate secid if there is one, - * otherwise 0 - */ -u32 smack_to_secid(const char *smack) -{ - struct smack_known *skp = smk_find_entry(smack); - - if (skp == NULL) - return 0; - return skp->smk_secid; -} diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 00443a9039b8..93dc876734a4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -78,8 +78,8 @@ static void smk_bu_mode(int mode, char *s) #endif #ifdef CONFIG_SECURITY_SMACK_BRINGUP -static int smk_bu_note(char *note, struct smack_known *sskp, char *osp, - int mode, int rc) +static int smk_bu_note(char *note, struct smack_known *sskp, + struct smack_known *oskp, int mode, int rc) { char acc[SMK_NUM_ACCESS_TYPE + 1]; @@ -88,15 +88,16 @@ static int smk_bu_note(char *note, struct smack_known *sskp, char *osp, smk_bu_mode(mode, acc); pr_info("Smack Bringup: (%s %s %s) %s\n", - sskp->smk_known, osp, acc, note); + sskp->smk_known, oskp->smk_known, acc, note); return 0; } #else -#define smk_bu_note(note, sskp, osp, mode, RC) (RC) +#define smk_bu_note(note, sskp, oskp, mode, RC) (RC) #endif #ifdef CONFIG_SECURITY_SMACK_BRINGUP -static int smk_bu_current(char *note, char *osp, int mode, int rc) +static int smk_bu_current(char *note, struct smack_known *oskp, + int mode, int rc) { struct task_smack *tsp = current_security(); char acc[SMK_NUM_ACCESS_TYPE + 1]; @@ -106,11 +107,12 @@ static int smk_bu_current(char *note, char *osp, int mode, int rc) smk_bu_mode(mode, acc); pr_info("Smack Bringup: (%s %s %s) %s %s\n", - tsp->smk_task->smk_known, osp, acc, current->comm, note); + tsp->smk_task->smk_known, oskp->smk_known, + acc, current->comm, note); return 0; } #else -#define smk_bu_current(note, osp, mode, RC) (RC) +#define smk_bu_current(note, oskp, mode, RC) (RC) #endif #ifdef CONFIG_SECURITY_SMACK_BRINGUP @@ -144,7 +146,7 @@ static int smk_bu_inode(struct inode *inode, int mode, int rc) smk_bu_mode(mode, acc); pr_info("Smack Bringup: (%s %s %s) inode=(%s %ld) %s\n", - tsp->smk_task->smk_known, smk_of_inode(inode), acc, + tsp->smk_task->smk_known, smk_of_inode(inode)->smk_known, acc, inode->i_sb->s_id, inode->i_ino, current->comm); return 0; } @@ -188,7 +190,7 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file, smk_bu_mode(mode, acc); pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n", - sskp->smk_known, smk_of_inode(inode), acc, + sskp->smk_known, smk_of_inode(inode)->smk_known, acc, inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name, current->comm); return 0; @@ -230,11 +232,11 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip, /** * new_inode_smack - allocate an inode security blob - * @smack: a pointer to the Smack label to use in the blob + * @skp: a pointer to the Smack label entry to use in the blob * * Returns the new blob or NULL if there's no memory available */ -struct inode_smack *new_inode_smack(char *smack) +struct inode_smack *new_inode_smack(struct smack_known *skp) { struct inode_smack *isp; @@ -242,7 +244,7 @@ struct inode_smack *new_inode_smack(char *smack) if (isp == NULL) return NULL; - isp->smk_inode = smack; + isp->smk_inode = skp; isp->smk_flags = 0; mutex_init(&isp->smk_lock); @@ -321,20 +323,20 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode) /** * smk_ptrace_rule_check - helper for ptrace access * @tracer: tracer process - * @tracee_label: label of the process that's about to be traced, - * the pointer must originate from smack structures + * @tracee_known: label entry of the process that's about to be traced * @mode: ptrace attachment mode (PTRACE_MODE_*) * @func: name of the function that called us, used for audit * * Returns 0 on access granted, -error on error */ -static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label, +static int smk_ptrace_rule_check(struct task_struct *tracer, + struct smack_known *tracee_known, unsigned int mode, const char *func) { int rc; struct smk_audit_info ad, *saip = NULL; struct task_smack *tsp; - struct smack_known *skp; + struct smack_known *tracer_known; if ((mode & PTRACE_MODE_NOAUDIT) == 0) { smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK); @@ -343,12 +345,12 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label, } tsp = task_security(tracer); - skp = smk_of_task(tsp); + tracer_known = smk_of_task(tsp); if ((mode & PTRACE_MODE_ATTACH) && (smack_ptrace_rule == SMACK_PTRACE_EXACT || smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) { - if (skp->smk_known == tracee_label) + if (tracer_known->smk_known == tracee_known->smk_known) rc = 0; else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN) rc = -EACCES; @@ -358,13 +360,15 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label, rc = -EACCES; if (saip) - smack_log(skp->smk_known, tracee_label, 0, rc, saip); + smack_log(tracer_known->smk_known, + tracee_known->smk_known, + 0, rc, saip); return rc; } /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */ - rc = smk_tskacc(tsp, tracee_label, smk_ptrace_mode(mode), saip); + rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip); return rc; } @@ -393,7 +397,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) skp = smk_of_task(task_security(ctp)); - rc = smk_ptrace_rule_check(current, skp->smk_known, mode, __func__); + rc = smk_ptrace_rule_check(current, skp, mode, __func__); return rc; } @@ -416,8 +420,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp) skp = smk_of_task(current_security()); - rc = smk_ptrace_rule_check(ptp, skp->smk_known, - PTRACE_MODE_ATTACH, __func__); + rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__); return rc; } @@ -461,10 +464,10 @@ static int smack_sb_alloc_security(struct super_block *sb) if (sbsp == NULL) return -ENOMEM; - sbsp->smk_root = smack_known_floor.smk_known; - sbsp->smk_default = smack_known_floor.smk_known; - sbsp->smk_floor = smack_known_floor.smk_known; - sbsp->smk_hat = smack_known_hat.smk_known; + sbsp->smk_root = &smack_known_floor; + sbsp->smk_default = &smack_known_floor; + sbsp->smk_floor = &smack_known_floor; + sbsp->smk_hat = &smack_known_hat; /* * smk_initialized will be zero from kzalloc. */ @@ -548,7 +551,6 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) struct smack_known *skp; char *op; char *commap; - char *nsp; int transmute = 0; int specified = 0; @@ -564,38 +566,38 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { op += strlen(SMK_FSHAT); - nsp = smk_import(op, 0); - if (nsp != NULL) { - sp->smk_hat = nsp; + skp = smk_import_entry(op, 0); + if (skp != NULL) { + sp->smk_hat = skp; specified = 1; } } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { op += strlen(SMK_FSFLOOR); - nsp = smk_import(op, 0); - if (nsp != NULL) { - sp->smk_floor = nsp; + skp = smk_import_entry(op, 0); + if (skp != NULL) { + sp->smk_floor = skp; specified = 1; } } else if (strncmp(op, SMK_FSDEFAULT, strlen(SMK_FSDEFAULT)) == 0) { op += strlen(SMK_FSDEFAULT); - nsp = smk_import(op, 0); - if (nsp != NULL) { - sp->smk_default = nsp; + skp = smk_import_entry(op, 0); + if (skp != NULL) { + sp->smk_default = skp; specified = 1; } } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { op += strlen(SMK_FSROOT); - nsp = smk_import(op, 0); - if (nsp != NULL) { - sp->smk_root = nsp; + skp = smk_import_entry(op, 0); + if (skp != NULL) { + sp->smk_root = skp; specified = 1; } } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { op += strlen(SMK_FSTRANS); - nsp = smk_import(op, 0); - if (nsp != NULL) { - sp->smk_root = nsp; + skp = smk_import_entry(op, 0); + if (skp != NULL) { + sp->smk_root = skp; transmute = 1; specified = 1; } @@ -612,8 +614,8 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) * Unprivileged mounts get root and default from the caller. */ skp = smk_of_current(); - sp->smk_root = skp->smk_known; - sp->smk_default = skp->smk_known; + sp->smk_root = skp; + sp->smk_default = skp; } /* * Initialize the root inode. @@ -690,7 +692,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) tracer = ptrace_parent(current); if (likely(tracer != NULL)) rc = smk_ptrace_rule_check(tracer, - isp->smk_task->smk_known, + isp->smk_task, PTRACE_MODE_ATTACH, __func__); rcu_read_unlock(); @@ -751,7 +753,7 @@ static int smack_inode_alloc_security(struct inode *inode) { struct smack_known *skp = smk_of_current(); - inode->i_security = new_inode_smack(skp->smk_known); + inode->i_security = new_inode_smack(skp); if (inode->i_security == NULL) return -ENOMEM; return 0; @@ -786,8 +788,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, { struct inode_smack *issp = inode->i_security; struct smack_known *skp = smk_of_current(); - char *isp = smk_of_inode(inode); - char *dsp = smk_of_inode(dir); + struct smack_known *isp = smk_of_inode(inode); + struct smack_known *dsp = smk_of_inode(dir); int may; if (name) @@ -795,7 +797,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, if (value) { rcu_read_lock(); - may = smk_access_entry(skp->smk_known, dsp, &skp->smk_rules); + may = smk_access_entry(skp->smk_known, dsp->smk_known, + &skp->smk_rules); rcu_read_unlock(); /* @@ -810,13 +813,13 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, issp->smk_flags |= SMK_INODE_CHANGED; } - *value = kstrdup(isp, GFP_NOFS); + *value = kstrdup(isp->smk_known, GFP_NOFS); if (*value == NULL) return -ENOMEM; } if (len) - *len = strlen(isp); + *len = strlen(isp->smk_known); return 0; } @@ -832,7 +835,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { - char *isp; + struct smack_known *isp; struct smk_audit_info ad; int rc; @@ -939,7 +942,7 @@ static int smack_inode_rename(struct inode *old_inode, struct dentry *new_dentry) { int rc; - char *isp; + struct smack_known *isp; struct smk_audit_info ad; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); @@ -1127,9 +1130,9 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, if (strcmp(name, XATTR_NAME_SMACK) == 0) { skp = smk_import_entry(value, size); if (skp != NULL) - isp->smk_inode = skp->smk_known; + isp->smk_inode = skp; else - isp->smk_inode = smack_known_invalid.smk_known; + isp->smk_inode = &smack_known_invalid; } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { skp = smk_import_entry(value, size); if (skp != NULL) @@ -1238,14 +1241,14 @@ static int smack_inode_getsecurity(const struct inode *inode, struct socket *sock; struct super_block *sbp; struct inode *ip = (struct inode *)inode; - char *isp; + struct smack_known *isp; int ilen; int rc = 0; if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { isp = smk_of_inode(inode); - ilen = strlen(isp); - *buffer = isp; + ilen = strlen(isp->smk_known); + *buffer = isp->smk_known; return ilen; } @@ -1263,15 +1266,15 @@ static int smack_inode_getsecurity(const struct inode *inode, ssp = sock->sk->sk_security; if (strcmp(name, XATTR_SMACK_IPIN) == 0) - isp = ssp->smk_in->smk_known; + isp = ssp->smk_in; else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) - isp = ssp->smk_out->smk_known; + isp = ssp->smk_out; else return -EOPNOTSUPP; - ilen = strlen(isp); + ilen = strlen(isp->smk_known); if (rc == 0) { - *buffer = isp; + *buffer = isp->smk_known; rc = ilen; } @@ -1307,7 +1310,7 @@ static void smack_inode_getsecid(const struct inode *inode, u32 *secid) { struct inode_smack *isp = inode->i_security; - *secid = smack_to_secid(isp->smk_inode); + *secid = isp->smk_inode->smk_secid; } /* @@ -1346,7 +1349,7 @@ static int smack_file_alloc_security(struct file *file) { struct smack_known *skp = smk_of_current(); - file->f_security = skp->smk_known; + file->f_security = skp; return 0; } @@ -1474,7 +1477,7 @@ static int smack_mmap_file(struct file *file, struct smack_known *mkp; struct smack_rule *srp; struct task_smack *tsp; - char *osmack; + struct smack_known *okp; struct inode_smack *isp; int may; int mmay; @@ -1500,18 +1503,19 @@ static int smack_mmap_file(struct file *file, * to that rule's object label. */ list_for_each_entry_rcu(srp, &skp->smk_rules, list) { - osmack = srp->smk_object; + okp = srp->smk_object; /* * Matching labels always allows access. */ - if (mkp->smk_known == osmack) + if (mkp->smk_known == okp->smk_known) continue; /* * If there is a matching local rule take * that into account as well. */ - may = smk_access_entry(srp->smk_subject->smk_known, osmack, - &tsp->smk_rules); + may = smk_access_entry(srp->smk_subject->smk_known, + okp->smk_known, + &tsp->smk_rules); if (may == -ENOENT) may = srp->smk_access; else @@ -1528,8 +1532,8 @@ static int smack_mmap_file(struct file *file, * If there isn't one a SMACK64MMAP subject * can't have as much access as current. */ - mmay = smk_access_entry(mkp->smk_known, osmack, - &mkp->smk_rules); + mmay = smk_access_entry(mkp->smk_known, okp->smk_known, + &mkp->smk_rules); if (mmay == -ENOENT) { rc = -EACCES; break; @@ -1538,8 +1542,8 @@ static int smack_mmap_file(struct file *file, * If there is a local entry it modifies the * potential access, too. */ - tmay = smk_access_entry(mkp->smk_known, osmack, - &tsp->smk_rules); + tmay = smk_access_entry(mkp->smk_known, okp->smk_known, + &tsp->smk_rules); if (tmay != -ENOENT) mmay &= tmay; @@ -1570,7 +1574,7 @@ static int smack_file_set_fowner(struct file *file) { struct smack_known *skp = smk_of_current(); - file->f_security = skp->smk_known; + file->f_security = skp; return 0; } @@ -1600,15 +1604,15 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, file = container_of(fown, struct file, f_owner); /* we don't log here as rc can be overriden */ - skp = smk_find_entry(file->f_security); - rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL); - rc = smk_bu_note("sigiotask", skp, tkp->smk_known, MAY_WRITE, rc); + skp = file->f_security; + rc = smk_access(skp, tkp, MAY_WRITE, NULL); + rc = smk_bu_note("sigiotask", skp, tkp, MAY_WRITE, rc); if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) rc = 0; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, tsk); - smack_log(file->f_security, tkp->smk_known, MAY_WRITE, rc, &ad); + smack_log(skp->smk_known, tkp->smk_known, MAY_WRITE, rc, &ad); return rc; } @@ -1805,7 +1809,7 @@ static int smack_kernel_create_files_as(struct cred *new, struct inode_smack *isp = inode->i_security; struct task_smack *tsp = new->security; - tsp->smk_forked = smk_find_entry(isp->smk_inode); + tsp->smk_forked = isp->smk_inode; tsp->smk_task = tsp->smk_forked; return 0; } @@ -1827,7 +1831,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access, smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); - rc = smk_curacc(skp->smk_known, access, &ad); + rc = smk_curacc(skp, access, &ad); rc = smk_bu_task(p, access, rc); return rc; } @@ -1992,7 +1996,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * can write the receiver. */ if (secid == 0) { - rc = smk_curacc(tkp->smk_known, MAY_WRITE, &ad); + rc = smk_curacc(tkp, MAY_WRITE, &ad); rc = smk_bu_task(p, MAY_WRITE, rc); return rc; } @@ -2002,8 +2006,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * we can't take privilege into account. */ skp = smack_from_secid(secid); - rc = smk_access(skp, tkp->smk_known, MAY_WRITE, &ad); - rc = smk_bu_note("USB signal", skp, tkp->smk_known, MAY_WRITE, rc); + rc = smk_access(skp, tkp, MAY_WRITE, &ad); + rc = smk_bu_note("USB signal", skp, tkp, MAY_WRITE, rc); return rc; } @@ -2038,7 +2042,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode) struct inode_smack *isp = inode->i_security; struct smack_known *skp = smk_of_task(task_security(p)); - isp->smk_inode = skp->smk_known; + isp->smk_inode = skp; } /* @@ -2096,7 +2100,7 @@ static void smack_sk_free_security(struct sock *sk) * * Returns the label of the far end or NULL if it's not special. */ -static char *smack_host_label(struct sockaddr_in *sip) +static struct smack_known *smack_host_label(struct sockaddr_in *sip) { struct smk_netlbladdr *snp; struct in_addr *siap = &sip->sin_addr; @@ -2113,7 +2117,7 @@ static char *smack_host_label(struct sockaddr_in *sip) 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) + if (snp->smk_label == &smack_cipso_option) return NULL; return snp->smk_label; } @@ -2178,13 +2182,13 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) struct smack_known *skp; int rc; int sk_lbl; - char *hostsp; + struct smack_known *hkp; struct socket_smack *ssp = sk->sk_security; struct smk_audit_info ad; rcu_read_lock(); - hostsp = smack_host_label(sap); - if (hostsp != NULL) { + hkp = smack_host_label(sap); + if (hkp != NULL) { #ifdef CONFIG_AUDIT struct lsm_network_audit net; @@ -2195,8 +2199,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) #endif sk_lbl = SMACK_UNLABELED_SOCKET; skp = ssp->smk_out; - rc = smk_access(skp, hostsp, MAY_WRITE, &ad); - rc = smk_bu_note("IPv4 host check", skp, hostsp, MAY_WRITE, rc); + rc = smk_access(skp, hkp, MAY_WRITE, &ad); + rc = smk_bu_note("IPv4 host check", skp, hkp, MAY_WRITE, rc); } else { sk_lbl = SMACK_CIPSO_SOCKET; rc = 0; @@ -2297,7 +2301,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, struct socket_smack *ssp = sk->sk_security; struct smack_known *skp; unsigned short port = 0; - char *object; + struct smack_known *object; struct smk_audit_info ad; int rc; #ifdef CONFIG_AUDIT @@ -2306,10 +2310,10 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, if (act == SMK_RECEIVING) { skp = smack_net_ambient; - object = ssp->smk_in->smk_known; + object = ssp->smk_in; } else { skp = ssp->smk_out; - object = smack_net_ambient->smk_known; + object = smack_net_ambient; } /* @@ -2336,7 +2340,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, list_for_each_entry(spp, &smk_ipv6_port_list, list) { if (spp->smk_port != port) continue; - object = spp->smk_in->smk_known; + object = spp->smk_in; if (act == SMK_CONNECTING) ssp->smk_packet = spp->smk_out; break; @@ -2387,7 +2391,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, return -EINVAL; if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { - nsp->smk_inode = skp->smk_known; + nsp->smk_inode = skp; nsp->smk_flags |= SMK_INODE_INSTANT; return 0; } @@ -2529,7 +2533,7 @@ static int smack_msg_msg_alloc_security(struct msg_msg *msg) { struct smack_known *skp = smk_of_current(); - msg->security = skp->smk_known; + msg->security = skp; return 0; } @@ -2550,9 +2554,9 @@ static void smack_msg_msg_free_security(struct msg_msg *msg) * * Returns a pointer to the smack value */ -static char *smack_of_shm(struct shmid_kernel *shp) +static struct smack_known *smack_of_shm(struct shmid_kernel *shp) { - return (char *)shp->shm_perm.security; + return (struct smack_known *)shp->shm_perm.security; } /** @@ -2566,7 +2570,7 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp) struct kern_ipc_perm *isp = &shp->shm_perm; struct smack_known *skp = smk_of_current(); - isp->security = skp->smk_known; + isp->security = skp; return 0; } @@ -2592,7 +2596,7 @@ static void smack_shm_free_security(struct shmid_kernel *shp) */ static int smk_curacc_shm(struct shmid_kernel *shp, int access) { - char *ssp = smack_of_shm(shp); + struct smack_known *ssp = smack_of_shm(shp); struct smk_audit_info ad; int rc; @@ -2677,9 +2681,9 @@ static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, * * Returns a pointer to the smack value */ -static char *smack_of_sem(struct sem_array *sma) +static struct smack_known *smack_of_sem(struct sem_array *sma) { - return (char *)sma->sem_perm.security; + return (struct smack_known *)sma->sem_perm.security; } /** @@ -2693,7 +2697,7 @@ static int smack_sem_alloc_security(struct sem_array *sma) struct kern_ipc_perm *isp = &sma->sem_perm; struct smack_known *skp = smk_of_current(); - isp->security = skp->smk_known; + isp->security = skp; return 0; } @@ -2719,7 +2723,7 @@ static void smack_sem_free_security(struct sem_array *sma) */ static int smk_curacc_sem(struct sem_array *sma, int access) { - char *ssp = smack_of_sem(sma); + struct smack_known *ssp = smack_of_sem(sma); struct smk_audit_info ad; int rc; @@ -2815,7 +2819,7 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq) struct kern_ipc_perm *kisp = &msq->q_perm; struct smack_known *skp = smk_of_current(); - kisp->security = skp->smk_known; + kisp->security = skp; return 0; } @@ -2836,11 +2840,11 @@ static void smack_msg_queue_free_security(struct msg_queue *msq) * smack_of_msq - the smack pointer for the msq * @msq: the object * - * Returns a pointer to the smack value + * Returns a pointer to the smack label entry */ -static char *smack_of_msq(struct msg_queue *msq) +static struct smack_known *smack_of_msq(struct msg_queue *msq) { - return (char *)msq->q_perm.security; + return (struct smack_known *)msq->q_perm.security; } /** @@ -2852,7 +2856,7 @@ static char *smack_of_msq(struct msg_queue *msq) */ static int smk_curacc_msq(struct msg_queue *msq, int access) { - char *msp = smack_of_msq(msq); + struct smack_known *msp = smack_of_msq(msq); struct smk_audit_info ad; int rc; @@ -2955,7 +2959,7 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, */ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) { - char *isp = ipp->security; + struct smack_known *iskp = ipp->security; int may = smack_flags_to_may(flag); struct smk_audit_info ad; int rc; @@ -2964,8 +2968,8 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); ad.a.u.ipc_id = ipp->id; #endif - rc = smk_curacc(isp, may, &ad); - rc = smk_bu_current("svipc", isp, may, rc); + rc = smk_curacc(iskp, may, &ad); + rc = smk_bu_current("svipc", iskp, may, rc); return rc; } @@ -2976,9 +2980,9 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) */ static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid) { - char *smack = ipp->security; + struct smack_known *iskp = ipp->security; - *secid = smack_to_secid(smack); + *secid = iskp->smk_secid; } /** @@ -2995,7 +2999,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) struct inode_smack *isp; struct smack_known *skp; struct smack_known *ckp = smk_of_current(); - char *final; + struct smack_known *final; char trattr[TRANS_TRUE_SIZE]; int transflag = 0; int rc; @@ -3035,8 +3039,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * so there's no opportunity to set the mount * options. */ - sbsp->smk_root = smack_known_star.smk_known; - sbsp->smk_default = smack_known_star.smk_known; + sbsp->smk_root = &smack_known_star; + sbsp->smk_default = &smack_known_star; } isp->smk_inode = sbsp->smk_root; isp->smk_flags |= SMK_INODE_INSTANT; @@ -3066,7 +3070,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * * Cgroupfs is special */ - final = smack_known_star.smk_known; + final = &smack_known_star; break; case DEVPTS_SUPER_MAGIC: /* @@ -3074,7 +3078,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * Programs that change smack have to treat the * pty with respect. */ - final = ckp->smk_known; + final = ckp; break; case PROC_SUPER_MAGIC: /* @@ -3088,7 +3092,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * but watch out, because they're volitile, * getting recreated on every reboot. */ - final = smack_known_star.smk_known; + final = &smack_known_star; /* * No break. * @@ -3107,7 +3111,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * UNIX domain sockets use lower level socket data. */ if (S_ISSOCK(inode->i_mode)) { - final = smack_known_star.smk_known; + final = &smack_known_star; break; } /* @@ -3124,7 +3128,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) dp = dget(opt_dentry); skp = smk_fetch(XATTR_NAME_SMACK, inode, dp); if (skp != NULL) - final = skp->smk_known; + final = skp; /* * Transmuting directory @@ -3173,7 +3177,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) } if (final == NULL) - isp->smk_inode = ckp->smk_known; + isp->smk_inode = ckp; else isp->smk_inode = final; @@ -3298,12 +3302,11 @@ static int smack_unix_stream_connect(struct sock *sock, smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); smk_ad_setfield_u_net_sk(&ad, other); #endif - rc = smk_access(skp, okp->smk_known, MAY_WRITE, &ad); - rc = smk_bu_note("UDS connect", skp, okp->smk_known, - MAY_WRITE, rc); + rc = smk_access(skp, okp, MAY_WRITE, &ad); + rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc); if (rc == 0) { - rc = smk_access(okp, skp->smk_known, MAY_WRITE, NULL); - rc = smk_bu_note("UDS connect", okp, skp->smk_known, + rc = smk_access(okp, skp, MAY_WRITE, NULL); + rc = smk_bu_note("UDS connect", okp, skp, MAY_WRITE, rc); } } @@ -3331,7 +3334,6 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) { struct socket_smack *ssp = sock->sk->sk_security; struct socket_smack *osp = other->sk->sk_security; - struct smack_known *skp; struct smk_audit_info ad; int rc; @@ -3345,10 +3347,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) if (smack_privileged(CAP_MAC_OVERRIDE)) return 0; - skp = ssp->smk_out; - rc = smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad); - rc = smk_bu_note("UDS send", skp, osp->smk_in->smk_known, - MAY_WRITE, rc); + rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); + rc = smk_bu_note("UDS send", ssp->smk_out, osp->smk_in, MAY_WRITE, rc); return rc; } @@ -3563,8 +3563,8 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) * This is the simplist possible security model * for networking. */ - rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad); - rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in->smk_known, + rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); + rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in, MAY_WRITE, rc); if (rc != 0) netlbl_skbuff_err(skb, rc, 0); @@ -3708,7 +3708,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct netlbl_lsm_secattr secattr; struct sockaddr_in addr; struct iphdr *hdr; - char *hsp; + struct smack_known *hskp; int rc; struct smk_audit_info ad; #ifdef CONFIG_AUDIT @@ -3745,9 +3745,8 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, * Receiving a packet requires that the other end be able to write * here. Read access is not required. */ - rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad); - rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in->smk_known, - MAY_WRITE, rc); + rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); + rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in, MAY_WRITE, rc); if (rc != 0) return rc; @@ -3765,10 +3764,10 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, hdr = ip_hdr(skb); addr.sin_addr.s_addr = hdr->saddr; rcu_read_lock(); - hsp = smack_host_label(&addr); + hskp = smack_host_label(&addr); rcu_read_unlock(); - if (hsp == NULL) + if (hskp == NULL) rc = netlbl_req_setattr(req, &skp->smk_netlabel); else netlbl_req_delattr(req); @@ -3820,7 +3819,7 @@ static int smack_key_alloc(struct key *key, const struct cred *cred, { struct smack_known *skp = smk_of_task(cred->security); - key->security = skp->smk_known; + key->security = skp; return 0; } @@ -3909,6 +3908,7 @@ static int smack_key_permission(key_ref_t key_ref, */ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) { + struct smack_known *skp; char **rule = (char **)vrule; *rule = NULL; @@ -3918,7 +3918,9 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) if (op != Audit_equal && op != Audit_not_equal) return -EINVAL; - *rule = smk_import(rulestr, 0); + skp = smk_import_entry(rulestr, 0); + if (skp) + *rule = skp->smk_known; return 0; } @@ -4037,7 +4039,12 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) */ static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) { - *secid = smack_to_secid(secdata); + struct smack_known *skp = smk_find_entry(secdata); + + if (skp) + *secid = skp->smk_secid; + else + *secid = 0; return 0; } diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 49a2248b525c..bce4e8f1b267 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -131,14 +131,17 @@ LIST_HEAD(smack_rule_list); struct smack_parsed_rule { struct smack_known *smk_subject; - char *smk_object; + struct smack_known *smk_object; int smk_access1; int smk_access2; }; static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; -const char *smack_cipso_option = SMACK_CIPSO_OPTION; +struct smack_known smack_cipso_option = { + .smk_known = SMACK_CIPSO_OPTION, + .smk_secid = 0, +}; /* * Values for parsing cipso rules @@ -339,7 +342,7 @@ static int smk_fill_rule(const char *subject, const char *object, if (rule->smk_subject == NULL) return -EINVAL; - rule->smk_object = smk_import(object, len); + rule->smk_object = smk_import_entry(object, len); if (rule->smk_object == NULL) return -EINVAL; } else { @@ -359,7 +362,7 @@ static int smk_fill_rule(const char *subject, const char *object, kfree(cp); if (skp == NULL) return -ENOENT; - rule->smk_object = skp->smk_known; + rule->smk_object = skp; } rule->smk_access1 = smk_perm_from_str(access1); @@ -598,13 +601,15 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) * anything you read back. */ if (strlen(srp->smk_subject->smk_known) >= max || - strlen(srp->smk_object) >= max) + strlen(srp->smk_object->smk_known) >= max) return; if (srp->smk_access == 0) return; - seq_printf(s, "%s %s", srp->smk_subject->smk_known, srp->smk_object); + seq_printf(s, "%s %s", + srp->smk_subject->smk_known, + srp->smk_object->smk_known); seq_putc(s, ' '); @@ -1073,7 +1078,7 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v) for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++); seq_printf(s, "%u.%u.%u.%u/%d %s\n", - hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label); + hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label->smk_known); return 0; } @@ -1153,10 +1158,10 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new) static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct smk_netlbladdr *skp; + struct smk_netlbladdr *snp; struct sockaddr_in newname; char *smack; - char *sp; + struct smack_known *skp; char *data; char *host = (char *)&newname.sin_addr.s_addr; int rc; @@ -1219,15 +1224,15 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, * If smack begins with '-', it is an option, don't import it */ if (smack[0] != '-') { - sp = smk_import(smack, 0); - if (sp == NULL) { + skp = smk_import_entry(smack, 0); + if (skp == NULL) { rc = -EINVAL; goto free_out; } } else { /* check known options */ - if (strcmp(smack, smack_cipso_option) == 0) - sp = (char *)smack_cipso_option; + if (strcmp(smack, smack_cipso_option.smk_known) == 0) + skp = &smack_cipso_option; else { rc = -EINVAL; goto free_out; @@ -1250,9 +1255,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, nsa = newname.sin_addr.s_addr; /* try to find if the prefix is already in the list */ found = 0; - list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) { - if (skp->smk_host.sin_addr.s_addr == nsa && - skp->smk_mask.s_addr == mask.s_addr) { + 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) { found = 1; break; } @@ -1260,26 +1265,26 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, smk_netlabel_audit_set(&audit_info); if (found == 0) { - skp = kzalloc(sizeof(*skp), GFP_KERNEL); - if (skp == NULL) + snp = kzalloc(sizeof(*snp), GFP_KERNEL); + if (snp == NULL) rc = -ENOMEM; else { rc = 0; - skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; - skp->smk_mask.s_addr = mask.s_addr; - skp->smk_label = sp; - smk_netlbladdr_insert(skp); + snp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; + snp->smk_mask.s_addr = mask.s_addr; + snp->smk_label = skp; + smk_netlbladdr_insert(snp); } } else { /* we delete the unlabeled entry, only if the previous label * wasn't the special CIPSO option */ - if (skp->smk_label != smack_cipso_option) + if (snp->smk_label != &smack_cipso_option) rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, - &skp->smk_host.sin_addr, &skp->smk_mask, + &snp->smk_host.sin_addr, &snp->smk_mask, PF_INET, &audit_info); else rc = 0; - skp->smk_label = sp; + snp->smk_label = skp; } /* @@ -1287,10 +1292,10 @@ 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 && sp != smack_cipso_option) + if (rc == 0 && skp != &smack_cipso_option) rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, - &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET, - smack_to_secid(skp->smk_label), &audit_info); + &snp->smk_host.sin_addr, &snp->smk_mask, PF_INET, + snp->smk_label->smk_secid, &audit_info); if (rc == 0) rc = count; -- GitLab From 6bb86fefa086faba7b60bb452300b76a47cde1a5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 30 Aug 2014 16:39:09 -0300 Subject: [PATCH 0794/5088] libahci_platform: Staticize ahci_platform_able_phys() ahci_platform_enable_phys() and ahci_platform_disable_phys() are currently exported, but they are not used anywhere else other than libahci_platform.c. So make them static and do not export them to fix the following sparse warnings: drivers/ata/libahci_platform.c:52:5: warning: symbol 'ahci_platform_enable_phys' was not declared. Should it be static? drivers/ata/libahci_platform.c:88:6: warning: symbol 'ahci_platform_disable_phys' was not declared. Should it be static? Signed-off-by: Fabio Estevam Signed-off-by: Tejun Heo --- drivers/ata/libahci_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index c0510de8a4c9..c7f787e9939b 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -49,7 +49,7 @@ static struct scsi_host_template ahci_platform_sht = { * RETURNS: * 0 on success otherwise a negative error code */ -int ahci_platform_enable_phys(struct ahci_host_priv *hpriv) +static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv) { int rc, i; @@ -77,7 +77,6 @@ int ahci_platform_enable_phys(struct ahci_host_priv *hpriv) } return rc; } -EXPORT_SYMBOL_GPL(ahci_platform_enable_phys); /** * ahci_platform_disable_phys - Disable PHYs @@ -85,7 +84,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_phys); * * This function disables all PHYs found in hpriv->phys. */ -void ahci_platform_disable_phys(struct ahci_host_priv *hpriv) +static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv) { int i; @@ -97,7 +96,6 @@ void ahci_platform_disable_phys(struct ahci_host_priv *hpriv) phy_exit(hpriv->phys[i]); } } -EXPORT_SYMBOL_GPL(ahci_platform_disable_phys); /** * ahci_platform_enable_clks - Enable platform clocks -- GitLab From 1bd06867f7f168273c80ba10ce4025a97be98305 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sun, 31 Aug 2014 10:57:09 +0200 Subject: [PATCH 0795/5088] ahci: ahci_p5wdh_workaround - constify DMI table The DMI table does not need to be written to, make it r/o. Signed-off-by: Mathias Krause Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index a29f8012fb08..c880699a7d0b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -780,7 +780,7 @@ static void ahci_pci_print_info(struct ata_host *host) */ static void ahci_p5wdh_workaround(struct ata_host *host) { - static struct dmi_system_id sysids[] = { + static const struct dmi_system_id sysids[] = { { .ident = "P5W DH Deluxe", .matches = { -- GitLab From bb693f13a0a535715034ce42405515ac3318c0e3 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 27 Aug 2014 15:04:29 -0400 Subject: [PATCH 0796/5088] x86: Remove set_pmd_pfn The last user of set_pmd_pfn() went away in commit f03574f2d5b2, so this has been dead code for over a year. Signed-off-by: Matthew Wilcox Signed-off-by: Thomas Gleixner arch/x86/include/asm/pgtable_32.h | 3 --- arch/x86/mm/pgtable_32.c | 35 ----------------------------------- 2 files changed, 38 deletions(-) --- arch/x86/include/asm/pgtable_32.h | 3 --- arch/x86/mm/pgtable_32.c | 35 ------------------------------- 2 files changed, 38 deletions(-) diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h index 9ee322103c6d..b6c0b404898a 100644 --- a/arch/x86/include/asm/pgtable_32.h +++ b/arch/x86/include/asm/pgtable_32.h @@ -32,9 +32,6 @@ static inline void pgtable_cache_init(void) { } static inline void check_pgt_cache(void) { } void paging_init(void); -extern void set_pmd_pfn(unsigned long, unsigned long, pgprot_t); - - /* * Define this if things work differently on an i386 and an i486: * it will (on an i486) warn about kernel memory accesses that are diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c index 4dd8cf652579..75cc0978d45d 100644 --- a/arch/x86/mm/pgtable_32.c +++ b/arch/x86/mm/pgtable_32.c @@ -59,41 +59,6 @@ void set_pte_vaddr(unsigned long vaddr, pte_t pteval) __flush_tlb_one(vaddr); } -/* - * Associate a large virtual page frame with a given physical page frame - * and protection flags for that frame. pfn is for the base of the page, - * vaddr is what the page gets mapped to - both must be properly aligned. - * The pmd must already be instantiated. Assumes PAE mode. - */ -void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - - if (vaddr & (PMD_SIZE-1)) { /* vaddr is misaligned */ - printk(KERN_WARNING "set_pmd_pfn: vaddr misaligned\n"); - return; /* BUG(); */ - } - if (pfn & (PTRS_PER_PTE-1)) { /* pfn is misaligned */ - printk(KERN_WARNING "set_pmd_pfn: pfn misaligned\n"); - return; /* BUG(); */ - } - pgd = swapper_pg_dir + pgd_index(vaddr); - if (pgd_none(*pgd)) { - printk(KERN_WARNING "set_pmd_pfn: pgd_none\n"); - return; /* BUG(); */ - } - pud = pud_offset(pgd, vaddr); - pmd = pmd_offset(pud, vaddr); - set_pmd(pmd, pfn_pmd(pfn, flags)); - /* - * It's enough to flush this one mapping. - * (PGE mappings get flushed as well) - */ - __flush_tlb_one(vaddr); -} - unsigned long __FIXADDR_TOP = 0xfffff000; EXPORT_SYMBOL(__FIXADDR_TOP); -- GitLab From d0b3c3b6c26c6eed1ba3fa37242dfc8942b5e997 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jan 2014 13:00:24 +0100 Subject: [PATCH 0797/5088] drm/nouveau: add reservation to nouveau_gem_ioctl_cpu_prep Apart from some code inside ttm itself and nouveau_bo_vma_del, this is the only place where ttm_bo_wait is used without a reservation. Fix this so we can remove the fence_lock later on. After the switch to rcu the reservation lock will be removed again. Signed-off-by: Maarten Lankhorst Acked-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 292a677bfed4..0054315eb879 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -884,17 +884,31 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, struct drm_gem_object *gem; struct nouveau_bo *nvbo; bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT); - int ret = -EINVAL; + int ret; + struct nouveau_fence *fence = NULL; gem = drm_gem_object_lookup(dev, file_priv, req->handle); if (!gem) return -ENOENT; nvbo = nouveau_gem_object(gem); - spin_lock(&nvbo->bo.bdev->fence_lock); - ret = ttm_bo_wait(&nvbo->bo, true, true, no_wait); - spin_unlock(&nvbo->bo.bdev->fence_lock); + ret = ttm_bo_reserve(&nvbo->bo, true, false, false, NULL); + if (!ret) { + spin_lock(&nvbo->bo.bdev->fence_lock); + ret = ttm_bo_wait(&nvbo->bo, true, true, true); + if (!no_wait && ret) + fence = nouveau_fence_ref(nvbo->bo.sync_obj); + spin_unlock(&nvbo->bo.bdev->fence_lock); + + ttm_bo_unreserve(&nvbo->bo); + } drm_gem_object_unreference_unlocked(gem); + + if (fence) { + ret = nouveau_fence_wait(fence, true, no_wait); + nouveau_fence_unref(&fence); + } + return ret; } -- GitLab From bdaf7ddf652ef51fd363b052e320711c06f6f553 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jan 2014 13:02:14 +0100 Subject: [PATCH 0798/5088] drm/nouveau: require reservations for nouveau_fence_sync and nouveau_bo_fence This will ensure we always hold the required lock when calling those functions. Signed-off-by: Maarten Lankhorst Acked-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 2 ++ drivers/gpu/drm/nouveau/nouveau_display.c | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 0591ca0734e3..ed966f51e29b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1463,6 +1463,8 @@ nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence) struct nouveau_fence *new_fence = nouveau_fence_ref(fence); struct nouveau_fence *old_fence = NULL; + lockdep_assert_held(&nvbo->bo.resv->lock.base); + spin_lock(&nvbo->bo.bdev->fence_lock); old_fence = nvbo->bo.sync_obj; nvbo->bo.sync_obj = new_fence; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 65b4fd53dd4e..54b1f3d8fc7f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -717,6 +717,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, } mutex_lock(&cli->mutex); + ret = ttm_bo_reserve(&new_bo->bo, true, false, false, NULL); + if (ret) + goto fail_unpin; /* synchronise rendering channel with the kernel's channel */ spin_lock(&new_bo->bo.bdev->fence_lock); @@ -724,12 +727,18 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, spin_unlock(&new_bo->bo.bdev->fence_lock); ret = nouveau_fence_sync(fence, chan); nouveau_fence_unref(&fence); - if (ret) + if (ret) { + ttm_bo_unreserve(&new_bo->bo); goto fail_unpin; + } - ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL); - if (ret) - goto fail_unpin; + if (new_bo != old_bo) { + ttm_bo_unreserve(&new_bo->bo); + + ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL); + if (ret) + goto fail_unpin; + } /* Initialize a page flip struct */ *s = (struct nouveau_page_flip_state) -- GitLab From 7040138ff85501931138970663a988f48c0666f0 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jan 2014 13:07:01 +0100 Subject: [PATCH 0799/5088] drm/ttm: call ttm_bo_wait while inside a reservation This is the last remaining function that doesn't use the reservation lock completely to fence off access to a buffer. Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/ttm/ttm_bo.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index b992ec3c318a..4f1bc948bda0 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -503,17 +503,6 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, if (ret) return ret; - /* - * remove sync_obj with ttm_bo_wait, the wait should be - * finished, and no new wait object should have been added. - */ - spin_lock(&bdev->fence_lock); - ret = ttm_bo_wait(bo, false, false, true); - WARN_ON(ret); - spin_unlock(&bdev->fence_lock); - if (ret) - return ret; - spin_lock(&glob->lru_lock); ret = __ttm_bo_reserve(bo, false, true, false, NULL); @@ -529,8 +518,16 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, spin_unlock(&glob->lru_lock); return 0; } - } else - spin_unlock(&bdev->fence_lock); + + /* + * remove sync_obj with ttm_bo_wait, the wait should be + * finished, and no new wait object should have been added. + */ + spin_lock(&bdev->fence_lock); + ret = ttm_bo_wait(bo, false, false, true); + WARN_ON(ret); + } + spin_unlock(&bdev->fence_lock); if (ret || unlikely(list_empty(&bo->ddestroy))) { __ttm_bo_unreserve(bo); @@ -1524,6 +1521,8 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, void *sync_obj; int ret = 0; + lockdep_assert_held(&bo->resv->lock.base); + if (likely(bo->sync_obj == NULL)) return 0; -- GitLab From dd7cfd641228abb2669d8d047d5ec377b1835900 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jan 2014 13:07:31 +0100 Subject: [PATCH 0800/5088] drm/ttm: kill fence_lock No users are left, kill it off! :D Conversion to the reservation api is next on the list, after that the functionality can be restored with rcu. Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/nouveau/nouveau_bo.c | 25 +++----- drivers/gpu/drm/nouveau/nouveau_display.c | 6 +- drivers/gpu/drm/nouveau/nouveau_gem.c | 16 +---- drivers/gpu/drm/qxl/qxl_cmd.c | 2 - drivers/gpu/drm/qxl/qxl_fence.c | 4 -- drivers/gpu/drm/qxl/qxl_object.h | 2 - drivers/gpu/drm/qxl/qxl_release.c | 2 - drivers/gpu/drm/radeon/radeon_display.c | 7 +-- drivers/gpu/drm/radeon/radeon_object.c | 2 - drivers/gpu/drm/ttm/ttm_bo.c | 75 ++++++----------------- drivers/gpu/drm/ttm/ttm_bo_util.c | 5 -- drivers/gpu/drm/ttm/ttm_bo_vm.c | 3 - drivers/gpu/drm/ttm/ttm_execbuf_util.c | 2 - drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 4 -- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 16 ++--- include/drm/ttm/ttm_bo_api.h | 5 +- include/drm/ttm/ttm_bo_driver.h | 3 - 17 files changed, 37 insertions(+), 142 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index ed966f51e29b..8d8e5f6340d0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1212,9 +1212,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, } /* Fallback to software copy. */ - spin_lock(&bo->bdev->fence_lock); ret = ttm_bo_wait(bo, true, intr, no_wait_gpu); - spin_unlock(&bo->bdev->fence_lock); if (ret == 0) ret = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); @@ -1457,26 +1455,19 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) ttm_pool_unpopulate(ttm); } +static void +nouveau_bo_fence_unref(void **sync_obj) +{ + nouveau_fence_unref((struct nouveau_fence **)sync_obj); +} + void nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence) { - struct nouveau_fence *new_fence = nouveau_fence_ref(fence); - struct nouveau_fence *old_fence = NULL; - lockdep_assert_held(&nvbo->bo.resv->lock.base); - spin_lock(&nvbo->bo.bdev->fence_lock); - old_fence = nvbo->bo.sync_obj; - nvbo->bo.sync_obj = new_fence; - spin_unlock(&nvbo->bo.bdev->fence_lock); - - nouveau_fence_unref(&old_fence); -} - -static void -nouveau_bo_fence_unref(void **sync_obj) -{ - nouveau_fence_unref((struct nouveau_fence **)sync_obj); + nouveau_bo_fence_unref(&nvbo->bo.sync_obj); + nvbo->bo.sync_obj = nouveau_fence_ref(fence); } static void * diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 54b1f3d8fc7f..e6867b9ebb46 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -722,11 +722,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, goto fail_unpin; /* synchronise rendering channel with the kernel's channel */ - spin_lock(&new_bo->bo.bdev->fence_lock); - fence = nouveau_fence_ref(new_bo->bo.sync_obj); - spin_unlock(&new_bo->bo.bdev->fence_lock); - ret = nouveau_fence_sync(fence, chan); - nouveau_fence_unref(&fence); + ret = nouveau_fence_sync(new_bo->bo.sync_obj, chan); if (ret) { ttm_bo_unreserve(&new_bo->bo); goto fail_unpin; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 0054315eb879..1650c0bdb0fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -103,9 +103,7 @@ nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma) list_del(&vma->head); if (mapped) { - spin_lock(&nvbo->bo.bdev->fence_lock); fence = nouveau_fence_ref(nvbo->bo.sync_obj); - spin_unlock(&nvbo->bo.bdev->fence_lock); } if (fence) { @@ -430,17 +428,11 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv, static int validate_sync(struct nouveau_channel *chan, struct nouveau_bo *nvbo) { - struct nouveau_fence *fence = NULL; + struct nouveau_fence *fence = nvbo->bo.sync_obj; int ret = 0; - spin_lock(&nvbo->bo.bdev->fence_lock); - fence = nouveau_fence_ref(nvbo->bo.sync_obj); - spin_unlock(&nvbo->bo.bdev->fence_lock); - - if (fence) { + if (fence) ret = nouveau_fence_sync(fence, chan); - nouveau_fence_unref(&fence); - } return ret; } @@ -659,9 +651,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, data |= r->vor; } - spin_lock(&nvbo->bo.bdev->fence_lock); ret = ttm_bo_wait(&nvbo->bo, false, false, false); - spin_unlock(&nvbo->bo.bdev->fence_lock); if (ret) { NV_PRINTK(error, cli, "reloc wait_idle failed: %d\n", ret); break; @@ -894,11 +884,9 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, ret = ttm_bo_reserve(&nvbo->bo, true, false, false, NULL); if (!ret) { - spin_lock(&nvbo->bo.bdev->fence_lock); ret = ttm_bo_wait(&nvbo->bo, true, true, true); if (!no_wait && ret) fence = nouveau_fence_ref(nvbo->bo.sync_obj); - spin_unlock(&nvbo->bo.bdev->fence_lock); ttm_bo_unreserve(&nvbo->bo); } diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index eb89653a7a17..45fad7b45486 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -628,9 +628,7 @@ static int qxl_reap_surf(struct qxl_device *qdev, struct qxl_bo *surf, bool stal if (stall) mutex_unlock(&qdev->surf_evict_mutex); - spin_lock(&surf->tbo.bdev->fence_lock); ret = ttm_bo_wait(&surf->tbo, true, true, !stall); - spin_unlock(&surf->tbo.bdev->fence_lock); if (stall) mutex_lock(&qdev->surf_evict_mutex); diff --git a/drivers/gpu/drm/qxl/qxl_fence.c b/drivers/gpu/drm/qxl/qxl_fence.c index ae59e91cfb9a..c7248418117d 100644 --- a/drivers/gpu/drm/qxl/qxl_fence.c +++ b/drivers/gpu/drm/qxl/qxl_fence.c @@ -60,9 +60,6 @@ int qxl_fence_remove_release(struct qxl_fence *qfence, uint32_t rel_id) { void *ret; int retval = 0; - struct qxl_bo *bo = container_of(qfence, struct qxl_bo, fence); - - spin_lock(&bo->tbo.bdev->fence_lock); ret = radix_tree_delete(&qfence->tree, rel_id); if (ret == qfence) @@ -71,7 +68,6 @@ int qxl_fence_remove_release(struct qxl_fence *qfence, uint32_t rel_id) DRM_DEBUG("didn't find fence in radix tree for %d\n", rel_id); retval = -ENOENT; } - spin_unlock(&bo->tbo.bdev->fence_lock); return retval; } diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h index 83a423293afd..1edaf5768086 100644 --- a/drivers/gpu/drm/qxl/qxl_object.h +++ b/drivers/gpu/drm/qxl/qxl_object.h @@ -76,12 +76,10 @@ static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type, } return r; } - spin_lock(&bo->tbo.bdev->fence_lock); if (mem_type) *mem_type = bo->tbo.mem.mem_type; if (bo->tbo.sync_obj) r = ttm_bo_wait(&bo->tbo, true, true, no_wait); - spin_unlock(&bo->tbo.bdev->fence_lock); ttm_bo_unreserve(&bo->tbo); return r; } diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index 14e776f1d14e..2e5e38fee9b2 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -337,7 +337,6 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release) glob = bo->glob; spin_lock(&glob->lru_lock); - spin_lock(&bdev->fence_lock); list_for_each_entry(entry, &release->bos, head) { bo = entry->bo; @@ -352,7 +351,6 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release) __ttm_bo_unreserve(bo); entry->reserved = false; } - spin_unlock(&bdev->fence_lock); spin_unlock(&glob->lru_lock); ww_acquire_fini(&release->ticket); } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index bd0d687379ee..7d0a7abdab2a 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -476,11 +476,6 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, obj = new_radeon_fb->obj; new_rbo = gem_to_radeon_bo(obj); - spin_lock(&new_rbo->tbo.bdev->fence_lock); - if (new_rbo->tbo.sync_obj) - work->fence = radeon_fence_ref(new_rbo->tbo.sync_obj); - spin_unlock(&new_rbo->tbo.bdev->fence_lock); - /* pin the new buffer */ DRM_DEBUG_DRIVER("flip-ioctl() cur_rbo = %p, new_rbo = %p\n", work->old_rbo, new_rbo); @@ -499,6 +494,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, DRM_ERROR("failed to pin new rbo buffer before flip\n"); goto cleanup; } + work->fence = radeon_fence_ref(new_rbo->tbo.sync_obj); radeon_bo_get_tiling_flags(new_rbo, &tiling_flags, NULL); radeon_bo_unreserve(new_rbo); @@ -582,7 +578,6 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); radeon_fence_unref(&work->fence); kfree(work); - return r; } diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index c97a42432e2b..cbac963571c0 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -779,12 +779,10 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait) r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, NULL); if (unlikely(r != 0)) return r; - spin_lock(&bo->tbo.bdev->fence_lock); if (mem_type) *mem_type = bo->tbo.mem.mem_type; if (bo->tbo.sync_obj) r = ttm_bo_wait(&bo->tbo, true, true, no_wait); - spin_unlock(&bo->tbo.bdev->fence_lock); ttm_bo_unreserve(&bo->tbo); return r; } diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 4f1bc948bda0..195386f16ca4 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -415,24 +415,20 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) spin_lock(&glob->lru_lock); ret = __ttm_bo_reserve(bo, false, true, false, NULL); - spin_lock(&bdev->fence_lock); - (void) ttm_bo_wait(bo, false, false, true); - if (!ret && !bo->sync_obj) { - spin_unlock(&bdev->fence_lock); - put_count = ttm_bo_del_from_lru(bo); + if (!ret) { + (void) ttm_bo_wait(bo, false, false, true); - spin_unlock(&glob->lru_lock); - ttm_bo_cleanup_memtype_use(bo); + if (!bo->sync_obj) { + put_count = ttm_bo_del_from_lru(bo); - ttm_bo_list_ref_sub(bo, put_count, true); + spin_unlock(&glob->lru_lock); + ttm_bo_cleanup_memtype_use(bo); - return; - } - if (bo->sync_obj) - sync_obj = driver->sync_obj_ref(bo->sync_obj); - spin_unlock(&bdev->fence_lock); + ttm_bo_list_ref_sub(bo, put_count, true); - if (!ret) { + return; + } + sync_obj = driver->sync_obj_ref(bo->sync_obj); /* * Make NO_EVICT bos immediately available to @@ -481,7 +477,6 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, int put_count; int ret; - spin_lock(&bdev->fence_lock); ret = ttm_bo_wait(bo, false, false, true); if (ret && !no_wait_gpu) { @@ -493,7 +488,6 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, * no new sync objects can be attached. */ sync_obj = driver->sync_obj_ref(bo->sync_obj); - spin_unlock(&bdev->fence_lock); __ttm_bo_unreserve(bo); spin_unlock(&glob->lru_lock); @@ -523,11 +517,9 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, * remove sync_obj with ttm_bo_wait, the wait should be * finished, and no new wait object should have been added. */ - spin_lock(&bdev->fence_lock); ret = ttm_bo_wait(bo, false, false, true); WARN_ON(ret); } - spin_unlock(&bdev->fence_lock); if (ret || unlikely(list_empty(&bo->ddestroy))) { __ttm_bo_unreserve(bo); @@ -665,9 +657,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, struct ttm_placement placement; int ret = 0; - spin_lock(&bdev->fence_lock); ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); - spin_unlock(&bdev->fence_lock); if (unlikely(ret != 0)) { if (ret != -ERESTARTSYS) { @@ -958,7 +948,6 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo, { int ret = 0; struct ttm_mem_reg mem; - struct ttm_bo_device *bdev = bo->bdev; lockdep_assert_held(&bo->resv->lock.base); @@ -967,9 +956,7 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo, * Have the driver move function wait for idle when necessary, * instead of doing it here. */ - spin_lock(&bdev->fence_lock); ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); - spin_unlock(&bdev->fence_lock); if (ret) return ret; mem.num_pages = bo->num_pages; @@ -1459,7 +1446,6 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev, bdev->glob = glob; bdev->need_dma32 = need_dma32; bdev->val_seq = 0; - spin_lock_init(&bdev->fence_lock); mutex_lock(&glob->device_list_mutex); list_add_tail(&bdev->device_list, &glob->device_list); mutex_unlock(&glob->device_list_mutex); @@ -1517,7 +1503,6 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, bool lazy, bool interruptible, bool no_wait) { struct ttm_bo_driver *driver = bo->bdev->driver; - struct ttm_bo_device *bdev = bo->bdev; void *sync_obj; int ret = 0; @@ -1526,53 +1511,33 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, if (likely(bo->sync_obj == NULL)) return 0; - while (bo->sync_obj) { - + if (bo->sync_obj) { if (driver->sync_obj_signaled(bo->sync_obj)) { - void *tmp_obj = bo->sync_obj; - bo->sync_obj = NULL; + driver->sync_obj_unref(&bo->sync_obj); clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); - spin_unlock(&bdev->fence_lock); - driver->sync_obj_unref(&tmp_obj); - spin_lock(&bdev->fence_lock); - continue; + return 0; } if (no_wait) return -EBUSY; sync_obj = driver->sync_obj_ref(bo->sync_obj); - spin_unlock(&bdev->fence_lock); ret = driver->sync_obj_wait(sync_obj, lazy, interruptible); - if (unlikely(ret != 0)) { - driver->sync_obj_unref(&sync_obj); - spin_lock(&bdev->fence_lock); - return ret; - } - spin_lock(&bdev->fence_lock); - if (likely(bo->sync_obj == sync_obj)) { - void *tmp_obj = bo->sync_obj; - bo->sync_obj = NULL; + + if (likely(ret == 0)) { clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); - spin_unlock(&bdev->fence_lock); - driver->sync_obj_unref(&sync_obj); - driver->sync_obj_unref(&tmp_obj); - spin_lock(&bdev->fence_lock); - } else { - spin_unlock(&bdev->fence_lock); - driver->sync_obj_unref(&sync_obj); - spin_lock(&bdev->fence_lock); + driver->sync_obj_unref(&bo->sync_obj); } + driver->sync_obj_unref(&sync_obj); } - return 0; + return ret; } EXPORT_SYMBOL(ttm_bo_wait); int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait) { - struct ttm_bo_device *bdev = bo->bdev; int ret = 0; /* @@ -1582,9 +1547,7 @@ int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait) ret = ttm_bo_reserve(bo, true, no_wait, false, NULL); if (unlikely(ret != 0)) return ret; - spin_lock(&bdev->fence_lock); ret = ttm_bo_wait(bo, false, true, no_wait); - spin_unlock(&bdev->fence_lock); if (likely(ret == 0)) atomic_inc(&bo->cpu_writers); ttm_bo_unreserve(bo); @@ -1641,9 +1604,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) * Wait for GPU, then move to system cached. */ - spin_lock(&bo->bdev->fence_lock); ret = ttm_bo_wait(bo, false, false, false); - spin_unlock(&bo->bdev->fence_lock); if (unlikely(ret != 0)) goto out; diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 30e5d90cb7bc..495aebf0f9c3 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -466,12 +466,10 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, drm_vma_node_reset(&fbo->vma_node); atomic_set(&fbo->cpu_writers, 0); - spin_lock(&bdev->fence_lock); if (bo->sync_obj) fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj); else fbo->sync_obj = NULL; - spin_unlock(&bdev->fence_lock); kref_init(&fbo->list_kref); kref_init(&fbo->kref); fbo->destroy = &ttm_transfered_destroy; @@ -657,7 +655,6 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, struct ttm_buffer_object *ghost_obj; void *tmp_obj = NULL; - spin_lock(&bdev->fence_lock); if (bo->sync_obj) { tmp_obj = bo->sync_obj; bo->sync_obj = NULL; @@ -665,7 +662,6 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, bo->sync_obj = driver->sync_obj_ref(sync_obj); if (evict) { ret = ttm_bo_wait(bo, false, false, false); - spin_unlock(&bdev->fence_lock); if (tmp_obj) driver->sync_obj_unref(&tmp_obj); if (ret) @@ -688,7 +684,6 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, */ set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); - spin_unlock(&bdev->fence_lock); if (tmp_obj) driver->sync_obj_unref(&tmp_obj); diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 0ce48e5a9cb4..d05437f219e9 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -45,10 +45,8 @@ static int ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, struct vm_area_struct *vma, struct vm_fault *vmf) { - struct ttm_bo_device *bdev = bo->bdev; int ret = 0; - spin_lock(&bdev->fence_lock); if (likely(!test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags))) goto out_unlock; @@ -82,7 +80,6 @@ static int ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, VM_FAULT_NOPAGE; out_unlock: - spin_unlock(&bdev->fence_lock); return ret; } diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index e8dac8758528..0fbbbbd67afc 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -217,7 +217,6 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket, glob = bo->glob; spin_lock(&glob->lru_lock); - spin_lock(&bdev->fence_lock); list_for_each_entry(entry, list, head) { bo = entry->bo; @@ -227,7 +226,6 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket, __ttm_bo_unreserve(bo); entry->reserved = false; } - spin_unlock(&bdev->fence_lock); spin_unlock(&glob->lru_lock); if (ticket) ww_acquire_fini(ticket); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 37c093c0c7b8..c133b3d10de8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -863,11 +863,7 @@ static void vmw_move_notify(struct ttm_buffer_object *bo, */ static void vmw_swap_notify(struct ttm_buffer_object *bo) { - struct ttm_bo_device *bdev = bo->bdev; - - spin_lock(&bdev->fence_lock); ttm_bo_wait(bo, false, false, false); - spin_unlock(&bdev->fence_lock); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index a432c0db257c..1ee86bf82750 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -567,12 +567,13 @@ static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo, int ret; if (flags & drm_vmw_synccpu_allow_cs) { - struct ttm_bo_device *bdev = bo->bdev; + bool nonblock = !!(flags & drm_vmw_synccpu_dontblock); - spin_lock(&bdev->fence_lock); - ret = ttm_bo_wait(bo, false, true, - !!(flags & drm_vmw_synccpu_dontblock)); - spin_unlock(&bdev->fence_lock); + ret = ttm_bo_reserve(bo, true, nonblock, false, NULL); + if (!ret) { + ret = ttm_bo_wait(bo, false, true, nonblock); + ttm_bo_unreserve(bo); + } return ret; } @@ -1429,12 +1430,10 @@ void vmw_fence_single_bo(struct ttm_buffer_object *bo, else driver->sync_obj_ref(fence); - spin_lock(&bdev->fence_lock); old_fence_obj = bo->sync_obj; bo->sync_obj = fence; - spin_unlock(&bdev->fence_lock); if (old_fence_obj) vmw_fence_obj_unreference(&old_fence_obj); @@ -1475,7 +1474,6 @@ void vmw_resource_move_notify(struct ttm_buffer_object *bo, if (mem->mem_type != VMW_PL_MOB) { struct vmw_resource *res, *n; - struct ttm_bo_device *bdev = bo->bdev; struct ttm_validate_buffer val_buf; val_buf.bo = bo; @@ -1491,9 +1489,7 @@ void vmw_resource_move_notify(struct ttm_buffer_object *bo, list_del_init(&res->mob_head); } - spin_lock(&bdev->fence_lock); (void) ttm_bo_wait(bo, false, false, false); - spin_unlock(&bdev->fence_lock); } } diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index e3d39c80a091..5805f4a49478 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -237,10 +237,7 @@ struct ttm_buffer_object { struct list_head io_reserve_lru; /** - * Members protected by struct buffer_object_device::fence_lock - * In addition, setting sync_obj to anything else - * than NULL requires bo::reserved to be held. This allows for - * checking NULL while reserved but not holding the mentioned lock. + * Members protected by a bo reservation. */ void *sync_obj; diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 5c8bb5699a6f..e1ee141e26cc 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -521,8 +521,6 @@ struct ttm_bo_global { * * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver. * @man: An array of mem_type_managers. - * @fence_lock: Protects the synchronizing members on *all* bos belonging - * to this device. * @vma_manager: Address space manager * lru_lock: Spinlock that protects the buffer+device lru lists and * ddestroy lists. @@ -542,7 +540,6 @@ struct ttm_bo_device { struct ttm_bo_global *glob; struct ttm_bo_driver *driver; struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; - spinlock_t fence_lock; /* * Protected by internal locks. -- GitLab From 58b4d720c1620bbf09e42b4f218dcb2d0d8cdf3e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 9 Jan 2014 11:03:08 +0100 Subject: [PATCH 0801/5088] drm/ttm: add interruptible parameter to ttm_eu_reserve_buffers It seems some drivers really want this as a parameter, like vmwgfx. Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/qxl/qxl_release.c | 2 +- drivers/gpu/drm/radeon/radeon_object.c | 2 +- drivers/gpu/drm/radeon/radeon_vm.c | 2 +- drivers/gpu/drm/ttm/ttm_execbuf_util.c | 22 +++++++++++++--------- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 7 ++----- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 2 +- include/drm/ttm/ttm_execbuf_util.h | 9 +++++---- 7 files changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index 2e5e38fee9b2..656f9d3a946d 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -159,7 +159,7 @@ int qxl_release_reserve_list(struct qxl_release *release, bool no_intr) if (list_is_singular(&release->bos)) return 0; - ret = ttm_eu_reserve_buffers(&release->ticket, &release->bos); + ret = ttm_eu_reserve_buffers(&release->ticket, &release->bos, !no_intr); if (ret) return ret; diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index cbac963571c0..378fe9ea4d44 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -482,7 +482,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev, u64 bytes_moved = 0, initial_bytes_moved; u64 bytes_moved_threshold = radeon_bo_get_threshold_for_moves(rdev); - r = ttm_eu_reserve_buffers(ticket, head); + r = ttm_eu_reserve_buffers(ticket, head, true); if (unlikely(r != 0)) { return r; } diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index 4751c6728fe9..3d9a6a036f8a 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -399,7 +399,7 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev, INIT_LIST_HEAD(&head); list_add(&tv.head, &head); - r = ttm_eu_reserve_buffers(&ticket, &head); + r = ttm_eu_reserve_buffers(&ticket, &head, true); if (r) return r; diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index 0fbbbbd67afc..87d7deefc806 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -112,7 +112,7 @@ EXPORT_SYMBOL(ttm_eu_backoff_reservation); */ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, - struct list_head *list) + struct list_head *list, bool intr) { struct ttm_bo_global *glob; struct ttm_validate_buffer *entry; @@ -140,7 +140,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, if (entry->reserved) continue; - ret = __ttm_bo_reserve(bo, true, (ticket == NULL), true, + ret = __ttm_bo_reserve(bo, intr, (ticket == NULL), true, ticket); if (ret == -EDEADLK) { @@ -153,13 +153,17 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, ttm_eu_backoff_reservation_locked(list); spin_unlock(&glob->lru_lock); ttm_eu_list_ref_sub(list); - ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, - ticket); - if (unlikely(ret != 0)) { - if (ret == -EINTR) - ret = -ERESTARTSYS; - goto err_fini; - } + + if (intr) { + ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, + ticket); + if (unlikely(ret != 0)) { + if (ret == -EINTR) + ret = -ERESTARTSYS; + goto err_fini; + } + } else + ww_mutex_lock_slow(&bo->resv->lock, ticket); entry->reserved = true; if (unlikely(atomic_read(&bo->cpu_writers) > 0)) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 7bfdaa163a33..24f067bf438d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -2496,7 +2496,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, if (unlikely(ret != 0)) goto out_err_nores; - ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes); + ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes, true); if (unlikely(ret != 0)) goto out_err; @@ -2684,10 +2684,7 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv, query_val.bo = ttm_bo_reference(dev_priv->dummy_query_bo); list_add_tail(&query_val.head, &validate_list); - do { - ret = ttm_eu_reserve_buffers(&ticket, &validate_list); - } while (ret == -ERESTARTSYS); - + ret = ttm_eu_reserve_buffers(&ticket, &validate_list, false); if (unlikely(ret != 0)) { vmw_execbuf_unpin_panic(dev_priv); goto out_no_reserve; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 1ee86bf82750..23169362bca8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -1216,7 +1216,7 @@ vmw_resource_check_buffer(struct vmw_resource *res, INIT_LIST_HEAD(&val_list); val_buf->bo = ttm_bo_reference(&res->backup->base); list_add_tail(&val_buf->head, &val_list); - ret = ttm_eu_reserve_buffers(NULL, &val_list); + ret = ttm_eu_reserve_buffers(NULL, &val_list, interruptible); if (unlikely(ret != 0)) goto out_no_reserve; diff --git a/include/drm/ttm/ttm_execbuf_util.h b/include/drm/ttm/ttm_execbuf_util.h index 16db7d01a336..fd95fd569ca3 100644 --- a/include/drm/ttm/ttm_execbuf_util.h +++ b/include/drm/ttm/ttm_execbuf_util.h @@ -73,6 +73,7 @@ extern void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket, * @ticket: [out] ww_acquire_ctx filled in by call, or NULL if only * non-blocking reserves should be tried. * @list: thread private list of ttm_validate_buffer structs. + * @intr: should the wait be interruptible * * Tries to reserve bos pointed to by the list entries for validation. * If the function returns 0, all buffers are marked as "unfenced", @@ -84,9 +85,9 @@ extern void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket, * CPU write reservations to be cleared, and for other threads to * unreserve their buffers. * - * This function may return -ERESTART or -EAGAIN if the calling process - * receives a signal while waiting. In that case, no buffers on the list - * will be reserved upon return. + * If intr is set to true, this function may return -ERESTARTSYS if the + * calling process receives a signal while waiting. In that case, no + * buffers on the list will be reserved upon return. * * Buffers reserved by this function should be unreserved by * a call to either ttm_eu_backoff_reservation() or @@ -95,7 +96,7 @@ extern void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket, */ extern int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, - struct list_head *list); + struct list_head *list, bool intr); /** * function ttm_eu_fence_buffer_objects. -- GitLab From 1f0dc9a59afeccb96a35ebec36661266260f5eee Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 9 Jan 2014 11:03:08 +0100 Subject: [PATCH 0802/5088] drm/ttm: kill off some members to ttm_validate_buffer This reorders the list to keep track of what buffers are reserved, so previous members are always unreserved. This gets rid of some bookkeeping that's no longer needed, while simplifying the code some. Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/qxl/qxl_release.c | 1 - drivers/gpu/drm/ttm/ttm_execbuf_util.c | 142 +++++++++--------------- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 1 - include/drm/ttm/ttm_execbuf_util.h | 3 - 4 files changed, 50 insertions(+), 97 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index 656f9d3a946d..4045ba873ab8 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -349,7 +349,6 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release) ttm_bo_add_to_lru(bo); __ttm_bo_unreserve(bo); - entry->reserved = false; } spin_unlock(&glob->lru_lock); ww_acquire_fini(&release->ticket); diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index 87d7deefc806..108730e9147b 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -32,20 +32,12 @@ #include #include -static void ttm_eu_backoff_reservation_locked(struct list_head *list) +static void ttm_eu_backoff_reservation_reverse(struct list_head *list, + struct ttm_validate_buffer *entry) { - struct ttm_validate_buffer *entry; - - list_for_each_entry(entry, list, head) { + list_for_each_entry_continue_reverse(entry, list, head) { struct ttm_buffer_object *bo = entry->bo; - if (!entry->reserved) - continue; - entry->reserved = false; - if (entry->removed) { - ttm_bo_add_to_lru(bo); - entry->removed = false; - } __ttm_bo_unreserve(bo); } } @@ -56,27 +48,9 @@ static void ttm_eu_del_from_lru_locked(struct list_head *list) list_for_each_entry(entry, list, head) { struct ttm_buffer_object *bo = entry->bo; - if (!entry->reserved) - continue; + unsigned put_count = ttm_bo_del_from_lru(bo); - if (!entry->removed) { - entry->put_count = ttm_bo_del_from_lru(bo); - entry->removed = true; - } - } -} - -static void ttm_eu_list_ref_sub(struct list_head *list) -{ - struct ttm_validate_buffer *entry; - - list_for_each_entry(entry, list, head) { - struct ttm_buffer_object *bo = entry->bo; - - if (entry->put_count) { - ttm_bo_list_ref_sub(bo, entry->put_count, true); - entry->put_count = 0; - } + ttm_bo_list_ref_sub(bo, put_count, true); } } @@ -91,11 +65,18 @@ void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket, entry = list_first_entry(list, struct ttm_validate_buffer, head); glob = entry->bo->glob; + spin_lock(&glob->lru_lock); - ttm_eu_backoff_reservation_locked(list); + list_for_each_entry(entry, list, head) { + struct ttm_buffer_object *bo = entry->bo; + + ttm_bo_add_to_lru(bo); + __ttm_bo_unreserve(bo); + } + spin_unlock(&glob->lru_lock); + if (ticket) ww_acquire_fini(ticket); - spin_unlock(&glob->lru_lock); } EXPORT_SYMBOL(ttm_eu_backoff_reservation); @@ -121,64 +102,55 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, if (list_empty(list)) return 0; - list_for_each_entry(entry, list, head) { - entry->reserved = false; - entry->put_count = 0; - entry->removed = false; - } - entry = list_first_entry(list, struct ttm_validate_buffer, head); glob = entry->bo->glob; if (ticket) ww_acquire_init(ticket, &reservation_ww_class); -retry: + list_for_each_entry(entry, list, head) { struct ttm_buffer_object *bo = entry->bo; - /* already slowpath reserved? */ - if (entry->reserved) - continue; - ret = __ttm_bo_reserve(bo, intr, (ticket == NULL), true, ticket); + if (!ret && unlikely(atomic_read(&bo->cpu_writers) > 0)) { + __ttm_bo_unreserve(bo); - if (ret == -EDEADLK) { - /* uh oh, we lost out, drop every reservation and try - * to only reserve this buffer, then start over if - * this succeeds. - */ - BUG_ON(ticket == NULL); - spin_lock(&glob->lru_lock); - ttm_eu_backoff_reservation_locked(list); - spin_unlock(&glob->lru_lock); - ttm_eu_list_ref_sub(list); - - if (intr) { - ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, - ticket); - if (unlikely(ret != 0)) { - if (ret == -EINTR) - ret = -ERESTARTSYS; - goto err_fini; - } - } else - ww_mutex_lock_slow(&bo->resv->lock, ticket); - - entry->reserved = true; - if (unlikely(atomic_read(&bo->cpu_writers) > 0)) { - ret = -EBUSY; - goto err; - } - goto retry; - } else if (ret) - goto err; - - entry->reserved = true; - if (unlikely(atomic_read(&bo->cpu_writers) > 0)) { ret = -EBUSY; - goto err; } + + if (!ret) + continue; + + /* uh oh, we lost out, drop every reservation and try + * to only reserve this buffer, then start over if + * this succeeds. + */ + ttm_eu_backoff_reservation_reverse(list, entry); + + if (ret == -EDEADLK && intr) { + ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, + ticket); + } else if (ret == -EDEADLK) { + ww_mutex_lock_slow(&bo->resv->lock, ticket); + ret = 0; + } + + if (unlikely(ret != 0)) { + if (ret == -EINTR) + ret = -ERESTARTSYS; + if (ticket) { + ww_acquire_done(ticket); + ww_acquire_fini(ticket); + } + return ret; + } + + /* move this item to the front of the list, + * forces correct iteration of the loop without keeping track + */ + list_del(&entry->head); + list_add(&entry->head, list); } if (ticket) @@ -186,20 +158,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, spin_lock(&glob->lru_lock); ttm_eu_del_from_lru_locked(list); spin_unlock(&glob->lru_lock); - ttm_eu_list_ref_sub(list); return 0; - -err: - spin_lock(&glob->lru_lock); - ttm_eu_backoff_reservation_locked(list); - spin_unlock(&glob->lru_lock); - ttm_eu_list_ref_sub(list); -err_fini: - if (ticket) { - ww_acquire_done(ticket); - ww_acquire_fini(ticket); - } - return ret; } EXPORT_SYMBOL(ttm_eu_reserve_buffers); @@ -228,7 +187,6 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket, bo->sync_obj = driver->sync_obj_ref(sync_obj); ttm_bo_add_to_lru(bo); __ttm_bo_unreserve(bo); - entry->reserved = false; } spin_unlock(&glob->lru_lock); if (ticket) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 24f067bf438d..b19b2b980cb4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -346,7 +346,6 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, ++sw_context->cur_val_buf; val_buf = &vval_buf->base; val_buf->bo = ttm_bo_reference(bo); - val_buf->reserved = false; list_add_tail(&val_buf->head, &sw_context->validate_nodes); vval_buf->validate_as_mob = validate_as_mob; } diff --git a/include/drm/ttm/ttm_execbuf_util.h b/include/drm/ttm/ttm_execbuf_util.h index fd95fd569ca3..8490cb8ee0d8 100644 --- a/include/drm/ttm/ttm_execbuf_util.h +++ b/include/drm/ttm/ttm_execbuf_util.h @@ -48,9 +48,6 @@ struct ttm_validate_buffer { struct list_head head; struct ttm_buffer_object *bo; - bool reserved; - bool removed; - int put_count; void *old_sync_obj; }; -- GitLab From 954605ca3f897ad617123279eb3404a404cce5ab Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 9 Jan 2014 11:03:12 +0100 Subject: [PATCH 0803/5088] drm/radeon: use common fence implementation for fences, v4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since v1: - Kill the sw interrupt dance, add and use radeon_irq_kms_sw_irq_get_delayed instead. - Change custom wait function, lockdep complained about it. Holding exclusive_lock in the wait function might cause deadlocks. Instead do all the processing in .enable_signaling, and wait on the global fence_queue to pick up gpu resets. - Process all fences in radeon_gpu_reset after reset to close a race with the trylock in enable_signaling. Changes since v2: - Small changes to work with the rewritten lockup recovery patches. Changes since v3: - Call radeon_fence_schedule_check when exclusive_lock cannot be acquired to always cause a wake up. - Reset irqs from hangup check. - Drop reading seqno in the callback, use cached value. - Fix indentation in radeon_fence_default_wait - Add a radeon_test_signaled function, drop a few test_bit calls. - Make to_radeon_fence global. Signed-off-by: Maarten Lankhorst Reviewed-by: Christian König --- drivers/gpu/drm/radeon/radeon.h | 23 ++- drivers/gpu/drm/radeon/radeon_device.c | 1 + drivers/gpu/drm/radeon/radeon_fence.c | 225 +++++++++++++++++++++--- drivers/gpu/drm/radeon/radeon_irq_kms.c | 15 ++ 4 files changed, 235 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 83a24614138a..d80dc547a105 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -354,17 +355,19 @@ struct radeon_fence_driver { /* sync_seq is protected by ring emission lock */ uint64_t sync_seq[RADEON_NUM_RINGS]; atomic64_t last_seq; - bool initialized; + bool initialized, delayed_irq; struct delayed_work lockup_work; }; struct radeon_fence { + struct fence base; + struct radeon_device *rdev; - struct kref kref; - /* protected by radeon_fence.lock */ uint64_t seq; /* RB, DMA, etc. */ unsigned ring; + + wait_queue_t fence_wake; }; int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring); @@ -782,6 +785,7 @@ struct radeon_irq { int radeon_irq_kms_init(struct radeon_device *rdev); void radeon_irq_kms_fini(struct radeon_device *rdev); void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring); +bool radeon_irq_kms_sw_irq_get_delayed(struct radeon_device *rdev, int ring); void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev, int ring); void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc); void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc); @@ -2308,6 +2312,7 @@ struct radeon_device { struct radeon_mman mman; struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS]; wait_queue_head_t fence_queue; + unsigned fence_context; struct mutex ring_lock; struct radeon_ring ring[RADEON_NUM_RINGS]; bool ib_pool_ready; @@ -2441,7 +2446,17 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v); /* * Cast helper */ -#define to_radeon_fence(p) ((struct radeon_fence *)(p)) +extern const struct fence_ops radeon_fence_ops; + +static inline struct radeon_fence *to_radeon_fence(struct fence *f) +{ + struct radeon_fence *__f = container_of(f, struct radeon_fence, base); + + if (__f->base.ops == &radeon_fence_ops) + return __f; + + return NULL; +} /* * Registers read & write functions. diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index d30f1cc1aa12..e84a76e6656a 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1253,6 +1253,7 @@ int radeon_device_init(struct radeon_device *rdev, for (i = 0; i < RADEON_NUM_RINGS; i++) { rdev->ring[i].idx = i; } + rdev->fence_context = fence_context_alloc(RADEON_NUM_RINGS); DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n", radeon_family_name[rdev->family], pdev->vendor, pdev->device, diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index ecdba3afa2c3..af9f2d6bd7d0 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -130,21 +130,59 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring) { + u64 seq = ++rdev->fence_drv[ring].sync_seq[ring]; + /* we are protected by the ring emission mutex */ *fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL); if ((*fence) == NULL) { return -ENOMEM; } - kref_init(&((*fence)->kref)); (*fence)->rdev = rdev; - (*fence)->seq = ++rdev->fence_drv[ring].sync_seq[ring]; + (*fence)->seq = seq; (*fence)->ring = ring; + fence_init(&(*fence)->base, &radeon_fence_ops, + &rdev->fence_queue.lock, rdev->fence_context + ring, seq); radeon_fence_ring_emit(rdev, ring, *fence); trace_radeon_fence_emit(rdev->ddev, ring, (*fence)->seq); radeon_fence_schedule_check(rdev, ring); return 0; } +/** + * radeon_fence_check_signaled - callback from fence_queue + * + * this function is called with fence_queue lock held, which is also used + * for the fence locking itself, so unlocked variants are used for + * fence_signal, and remove_wait_queue. + */ +static int radeon_fence_check_signaled(wait_queue_t *wait, unsigned mode, int flags, void *key) +{ + struct radeon_fence *fence; + u64 seq; + + fence = container_of(wait, struct radeon_fence, fence_wake); + + /* + * We cannot use radeon_fence_process here because we're already + * in the waitqueue, in a call from wake_up_all. + */ + seq = atomic64_read(&fence->rdev->fence_drv[fence->ring].last_seq); + if (seq >= fence->seq) { + int ret = fence_signal_locked(&fence->base); + + if (!ret) + FENCE_TRACE(&fence->base, "signaled from irq context\n"); + else + FENCE_TRACE(&fence->base, "was already signaled\n"); + + radeon_irq_kms_sw_irq_put(fence->rdev, fence->ring); + __remove_wait_queue(&fence->rdev->fence_queue, &fence->fence_wake); + fence_put(&fence->base); + } else + FENCE_TRACE(&fence->base, "pending\n"); + return 0; +} + /** * radeon_fence_activity - check for fence activity * @@ -242,6 +280,15 @@ static void radeon_fence_check_lockup(struct work_struct *work) return; } + if (fence_drv->delayed_irq && rdev->ddev->irq_enabled) { + unsigned long irqflags; + + fence_drv->delayed_irq = false; + spin_lock_irqsave(&rdev->irq.lock, irqflags); + radeon_irq_set(rdev); + spin_unlock_irqrestore(&rdev->irq.lock, irqflags); + } + if (radeon_fence_activity(rdev, ring)) wake_up_all(&rdev->fence_queue); @@ -275,21 +322,6 @@ void radeon_fence_process(struct radeon_device *rdev, int ring) wake_up_all(&rdev->fence_queue); } -/** - * radeon_fence_destroy - destroy a fence - * - * @kref: fence kref - * - * Frees the fence object (all asics). - */ -static void radeon_fence_destroy(struct kref *kref) -{ - struct radeon_fence *fence; - - fence = container_of(kref, struct radeon_fence, kref); - kfree(fence); -} - /** * radeon_fence_seq_signaled - check if a fence sequence number has signaled * @@ -318,6 +350,75 @@ static bool radeon_fence_seq_signaled(struct radeon_device *rdev, return false; } +static bool radeon_fence_is_signaled(struct fence *f) +{ + struct radeon_fence *fence = to_radeon_fence(f); + struct radeon_device *rdev = fence->rdev; + unsigned ring = fence->ring; + u64 seq = fence->seq; + + if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) { + return true; + } + + if (down_read_trylock(&rdev->exclusive_lock)) { + radeon_fence_process(rdev, ring); + up_read(&rdev->exclusive_lock); + + if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) { + return true; + } + } + return false; +} + +/** + * radeon_fence_enable_signaling - enable signalling on fence + * @fence: fence + * + * This function is called with fence_queue lock held, and adds a callback + * to fence_queue that checks if this fence is signaled, and if so it + * signals the fence and removes itself. + */ +static bool radeon_fence_enable_signaling(struct fence *f) +{ + struct radeon_fence *fence = to_radeon_fence(f); + struct radeon_device *rdev = fence->rdev; + + if (atomic64_read(&rdev->fence_drv[fence->ring].last_seq) >= fence->seq) + return false; + + if (down_read_trylock(&rdev->exclusive_lock)) { + radeon_irq_kms_sw_irq_get(rdev, fence->ring); + + if (radeon_fence_activity(rdev, fence->ring)) + wake_up_all_locked(&rdev->fence_queue); + + /* did fence get signaled after we enabled the sw irq? */ + if (atomic64_read(&rdev->fence_drv[fence->ring].last_seq) >= fence->seq) { + radeon_irq_kms_sw_irq_put(rdev, fence->ring); + up_read(&rdev->exclusive_lock); + return false; + } + + up_read(&rdev->exclusive_lock); + } else { + /* we're probably in a lockup, lets not fiddle too much */ + if (radeon_irq_kms_sw_irq_get_delayed(rdev, fence->ring)) + rdev->fence_drv[fence->ring].delayed_irq = true; + radeon_fence_schedule_check(rdev, fence->ring); + } + + fence->fence_wake.flags = 0; + fence->fence_wake.private = NULL; + fence->fence_wake.func = radeon_fence_check_signaled; + __add_wait_queue(&rdev->fence_queue, &fence->fence_wake); + fence_get(f); + + FENCE_TRACE(&fence->base, "armed on ring %i!\n", fence->ring); + return true; +} + /** * radeon_fence_signaled - check if a fence has signaled * @@ -330,8 +431,15 @@ bool radeon_fence_signaled(struct radeon_fence *fence) { if (!fence) return true; - if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) + + if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) { + int ret; + + ret = fence_signal(&fence->base); + if (!ret) + FENCE_TRACE(&fence->base, "signaled from radeon_fence_signaled\n"); return true; + } return false; } @@ -433,17 +541,15 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr) uint64_t seq[RADEON_NUM_RINGS] = {}; long r; - if (fence == NULL) { - WARN(1, "Querying an invalid fence : %p !\n", fence); - return -EINVAL; - } - seq[fence->ring] = fence->seq; r = radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, MAX_SCHEDULE_TIMEOUT); if (r < 0) { return r; } + r = fence_signal(&fence->base); + if (!r) + FENCE_TRACE(&fence->base, "signaled from fence_wait\n"); return 0; } @@ -557,7 +663,7 @@ int radeon_fence_wait_empty(struct radeon_device *rdev, int ring) */ struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence) { - kref_get(&fence->kref); + fence_get(&fence->base); return fence; } @@ -574,7 +680,7 @@ void radeon_fence_unref(struct radeon_fence **fence) *fence = NULL; if (tmp) { - kref_put(&tmp->kref, radeon_fence_destroy); + fence_put(&tmp->base); } } @@ -887,3 +993,72 @@ int radeon_debugfs_fence_init(struct radeon_device *rdev) return 0; #endif } + +static const char *radeon_fence_get_driver_name(struct fence *fence) +{ + return "radeon"; +} + +static const char *radeon_fence_get_timeline_name(struct fence *f) +{ + struct radeon_fence *fence = to_radeon_fence(f); + switch (fence->ring) { + case RADEON_RING_TYPE_GFX_INDEX: return "radeon.gfx"; + case CAYMAN_RING_TYPE_CP1_INDEX: return "radeon.cp1"; + case CAYMAN_RING_TYPE_CP2_INDEX: return "radeon.cp2"; + case R600_RING_TYPE_DMA_INDEX: return "radeon.dma"; + case CAYMAN_RING_TYPE_DMA1_INDEX: return "radeon.dma1"; + case R600_RING_TYPE_UVD_INDEX: return "radeon.uvd"; + case TN_RING_TYPE_VCE1_INDEX: return "radeon.vce1"; + case TN_RING_TYPE_VCE2_INDEX: return "radeon.vce2"; + default: WARN_ON_ONCE(1); return "radeon.unk"; + } +} + +static inline bool radeon_test_signaled(struct radeon_fence *fence) +{ + return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags); +} + +static signed long radeon_fence_default_wait(struct fence *f, bool intr, + signed long t) +{ + struct radeon_fence *fence = to_radeon_fence(f); + struct radeon_device *rdev = fence->rdev; + bool signaled; + + fence_enable_sw_signaling(&fence->base); + + /* + * This function has to return -EDEADLK, but cannot hold + * exclusive_lock during the wait because some callers + * may already hold it. This means checking needs_reset without + * lock, and not fiddling with any gpu internals. + * + * The callback installed with fence_enable_sw_signaling will + * run before our wait_event_*timeout call, so we will see + * both the signaled fence and the changes to needs_reset. + */ + + if (intr) + t = wait_event_interruptible_timeout(rdev->fence_queue, + ((signaled = radeon_test_signaled(fence)) || + rdev->needs_reset), t); + else + t = wait_event_timeout(rdev->fence_queue, + ((signaled = radeon_test_signaled(fence)) || + rdev->needs_reset), t); + + if (t > 0 && !signaled) + return -EDEADLK; + return t; +} + +const struct fence_ops radeon_fence_ops = { + .get_driver_name = radeon_fence_get_driver_name, + .get_timeline_name = radeon_fence_get_timeline_name, + .enable_signaling = radeon_fence_enable_signaling, + .signaled = radeon_fence_is_signaled, + .wait = radeon_fence_default_wait, + .release = NULL, +}; diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index f0bff4be67f1..7784911d78ef 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -323,6 +323,21 @@ void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring) } } +/** + * radeon_irq_kms_sw_irq_get_delayed - enable software interrupt + * + * @rdev: radeon device pointer + * @ring: ring whose interrupt you want to enable + * + * Enables the software interrupt for a specific ring (all asics). + * The software interrupt is generally used to signal a fence on + * a particular ring. + */ +bool radeon_irq_kms_sw_irq_get_delayed(struct radeon_device *rdev, int ring) +{ + return atomic_inc_return(&rdev->irq.ring_int[ring]) == 1; +} + /** * radeon_irq_kms_sw_irq_put - disable software interrupt * -- GitLab From 085f3ec6fd6c87907c4a19481dc13f02ecfcd316 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Sep 2014 12:46:37 +0300 Subject: [PATCH 0804/5088] ASoC: tlv320aic31xx: Correct interface register 2 variable name Rename iface_reg3 to iface_reg2 since this variable is actually used for interface register 2. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 0f64c7890eed..9f9d23b94c22 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -813,7 +813,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; u8 iface_reg1 = 0; - u8 iface_reg3 = 0; + u8 iface_reg2 = 0; u8 dsp_a_val = 0; dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt); @@ -838,7 +838,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, /* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: - iface_reg3 |= AIC31XX_BCLKINV_MASK; + iface_reg2 |= AIC31XX_BCLKINV_MASK; break; case SND_SOC_DAIFMT_IB_NF: break; @@ -870,7 +870,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, dsp_a_val); snd_soc_update_bits(codec, AIC31XX_IFACE2, AIC31XX_BCLKINV_MASK, - iface_reg3); + iface_reg2); return 0; } -- GitLab From 75c3daaad5a2f791e0fbad732690130ce1bc55d2 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 1 Sep 2014 08:47:50 +0800 Subject: [PATCH 0805/5088] ASoC: es8328: fix error return code in es8328_codec_probe() Fix to return a negative error code from the error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 7a9f65ad183d..3ff787063304 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -665,6 +665,7 @@ static int es8328_codec_probe(struct snd_soc_codec *codec) es8328->clk = devm_clk_get(codec->dev, NULL); if (IS_ERR(es8328->clk)) { dev_err(codec->dev, "codec clock missing or invalid\n"); + ret = PTR_ERR(es8328->clk); goto clk_fail; } -- GitLab From 068765ba7987e73d4381edfe47b70aa121c7155c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Sep 2014 13:47:49 +0200 Subject: [PATCH 0806/5088] PM / sleep: Mechanism for aborting system suspends unconditionally It sometimes may be necessary to abort a system suspend in progress or wake up the system from suspend-to-idle even if the pm_wakeup_event()/pm_stay_awake() mechanism is not enabled. For this purpose, introduce a new global variable pm_abort_suspend and make pm_wakeup_pending() check its value. Also add routines for manipulating that variable. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/wakeup.c | 16 +++++++++++++++- include/linux/suspend.h | 4 ++++ kernel/power/process.c | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index eb1bd2ecad8b..c2744b30d5d9 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -24,6 +24,9 @@ */ bool events_check_enabled __read_mostly; +/* If set and the system is suspending, terminate the suspend. */ +static bool pm_abort_suspend __read_mostly; + /* * Combined counters of registered wakeup events and wakeup events in progress. * They need to be modified together atomically, so it's better to use one @@ -719,7 +722,18 @@ bool pm_wakeup_pending(void) pm_print_active_wakeup_sources(); } - return ret; + return ret || pm_abort_suspend; +} + +void pm_system_wakeup(void) +{ + pm_abort_suspend = true; + freeze_wake(); +} + +void pm_wakeup_clear(void) +{ + pm_abort_suspend = false; } /** diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 519064e0c943..06a9910827c2 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -371,6 +371,8 @@ extern int unregister_pm_notifier(struct notifier_block *nb); extern bool events_check_enabled; extern bool pm_wakeup_pending(void); +extern void pm_system_wakeup(void); +extern void pm_wakeup_clear(void); extern bool pm_get_wakeup_count(unsigned int *count, bool block); extern bool pm_save_wakeup_count(unsigned int count); extern void pm_wakep_autosleep_enabled(bool set); @@ -418,6 +420,8 @@ static inline int unregister_pm_notifier(struct notifier_block *nb) #define pm_notifier(fn, pri) do { (void)(fn); } while (0) static inline bool pm_wakeup_pending(void) { return false; } +static inline void pm_system_wakeup(void) {} +static inline void pm_wakeup_clear(void) {} static inline void lock_system_sleep(void) {} static inline void unlock_system_sleep(void) {} diff --git a/kernel/power/process.c b/kernel/power/process.c index 4ee194eb524b..7b323221b9ee 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -129,6 +129,7 @@ int freeze_processes(void) if (!pm_freezing) atomic_inc(&system_freezing_cnt); + pm_wakeup_clear(); printk("Freezing user space processes ... "); pm_freezing = true; error = try_to_freeze_tasks(true); -- GitLab From 8df2e02c5c4de9e65ee60153dd9c442356534ad9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 28 Aug 2014 11:49:28 +0200 Subject: [PATCH 0807/5088] genirq: Move suspend/resume logic into irq/pm code No functional change. Preparatory patch for cleaning up the suspend abort functionality. Update the comments while at it. Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- kernel/irq/internals.h | 4 ++-- kernel/irq/manage.c | 28 +++++---------------------- kernel/irq/pm.c | 44 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 099ea2e0eb88..af2821178900 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -63,8 +63,8 @@ enum { extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, unsigned long flags); -extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp); -extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); +extern void __disable_irq(struct irq_desc *desc, unsigned int irq); +extern void __enable_irq(struct irq_desc *desc, unsigned int irq); extern int irq_startup(struct irq_desc *desc, bool resend); extern void irq_shutdown(struct irq_desc *desc); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 3dc6a61bf06a..fa564e8db996 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -382,14 +382,8 @@ setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) } #endif -void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend) +void __disable_irq(struct irq_desc *desc, unsigned int irq) { - if (suspend) { - if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND)) - return; - desc->istate |= IRQS_SUSPENDED; - } - if (!desc->depth++) irq_disable(desc); } @@ -401,7 +395,7 @@ static int __disable_irq_nosync(unsigned int irq) if (!desc) return -EINVAL; - __disable_irq(desc, irq, false); + __disable_irq(desc, irq); irq_put_desc_busunlock(desc, flags); return 0; } @@ -442,20 +436,8 @@ void disable_irq(unsigned int irq) } EXPORT_SYMBOL(disable_irq); -void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume) +void __enable_irq(struct irq_desc *desc, unsigned int irq) { - if (resume) { - if (!(desc->istate & IRQS_SUSPENDED)) { - if (!desc->action) - return; - if (!(desc->action->flags & IRQF_FORCE_RESUME)) - return; - /* Pretend that it got disabled ! */ - desc->depth++; - } - desc->istate &= ~IRQS_SUSPENDED; - } - switch (desc->depth) { case 0: err_out: @@ -497,7 +479,7 @@ void enable_irq(unsigned int irq) KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq)) goto out; - __enable_irq(desc, irq, false); + __enable_irq(desc, irq); out: irq_put_desc_busunlock(desc, flags); } @@ -1228,7 +1210,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) */ if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) { desc->istate &= ~IRQS_SPURIOUS_DISABLED; - __enable_irq(desc, irq, false); + __enable_irq(desc, irq); } raw_spin_unlock_irqrestore(&desc->lock, flags); diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index abcd6ca86cb7..b84141dcee5e 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -13,13 +13,26 @@ #include "internals.h" +static void suspend_device_irq(struct irq_desc *desc, int irq) +{ + if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND)) + return; + + desc->istate |= IRQS_SUSPENDED; + __disable_irq(desc, irq); +} + /** * suspend_device_irqs - disable all currently enabled interrupt lines * - * During system-wide suspend or hibernation device drivers need to be prevented - * from receiving interrupts and this function is provided for this purpose. - * It marks all interrupt lines in use, except for the timer ones, as disabled - * and sets the IRQS_SUSPENDED flag for each of them. + * During system-wide suspend or hibernation device drivers need to be + * prevented from receiving interrupts and this function is provided + * for this purpose. + * + * So we disable all interrupts and mark them IRQS_SUSPENDED except + * for those which are unused and those which are marked as not + * suspendable via an interrupt request with the flag IRQF_NO_SUSPEND + * set. */ void suspend_device_irqs(void) { @@ -30,7 +43,7 @@ void suspend_device_irqs(void) unsigned long flags; raw_spin_lock_irqsave(&desc->lock, flags); - __disable_irq(desc, irq, true); + suspend_device_irq(desc, irq); raw_spin_unlock_irqrestore(&desc->lock, flags); } @@ -40,6 +53,25 @@ void suspend_device_irqs(void) } EXPORT_SYMBOL_GPL(suspend_device_irqs); +static void resume_irq(struct irq_desc *desc, int irq) +{ + if (desc->istate & IRQS_SUSPENDED) + goto resume; + + if (!desc->action) + return; + + /* Interrupts marked with that flag are force reenabled */ + if (!(desc->action->flags & IRQF_FORCE_RESUME)) + return; + + /* Pretend that it got disabled ! */ + desc->depth++; +resume: + desc->istate &= ~IRQS_SUSPENDED; + __enable_irq(desc, irq); +} + static void resume_irqs(bool want_early) { struct irq_desc *desc; @@ -54,7 +86,7 @@ static void resume_irqs(bool want_early) continue; raw_spin_lock_irqsave(&desc->lock, flags); - __enable_irq(desc, irq, true); + resume_irq(desc, irq); raw_spin_unlock_irqrestore(&desc->lock, flags); } } -- GitLab From cab303be91dc47942bc25de33dc1140123540800 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 28 Aug 2014 11:44:31 +0200 Subject: [PATCH 0808/5088] genirq: Add sanity checks for PM options on shared interrupt lines Account the IRQF_NO_SUSPEND and IRQF_RESUME_EARLY actions on shared interrupt lines and yell loudly if there is a mismatch. Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- include/linux/irqdesc.h | 10 ++++++++++ kernel/irq/internals.h | 10 ++++++++++ kernel/irq/manage.c | 4 ++++ kernel/irq/pm.c | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+) diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 472c021a2d4f..cb1a31e448ae 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -36,6 +36,11 @@ struct irq_desc; * @threads_oneshot: bitfield to handle shared oneshot threads * @threads_active: number of irqaction threads currently running * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers + * @nr_actions: number of installed actions on this descriptor + * @no_suspend_depth: number of irqactions on a irq descriptor with + * IRQF_NO_SUSPEND set + * @force_resume_depth: number of irqactions on a irq descriptor with + * IRQF_FORCE_RESUME set * @dir: /proc/irq/ procfs entry * @name: flow handler name for /proc/interrupts output */ @@ -68,6 +73,11 @@ struct irq_desc { unsigned long threads_oneshot; atomic_t threads_active; wait_queue_head_t wait_for_threads; +#ifdef CONFIG_PM_SLEEP + unsigned int nr_actions; + unsigned int no_suspend_depth; + unsigned int force_resume_depth; +#endif #ifdef CONFIG_PROC_FS struct proc_dir_entry *dir; #endif diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index af2821178900..c402502a5111 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -194,3 +194,13 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *d __this_cpu_inc(*desc->kstat_irqs); __this_cpu_inc(kstat.irqs_sum); } + +#ifdef CONFIG_PM_SLEEP +void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action); +void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action); +#else +static inline void +irq_pm_install_action(struct irq_desc *desc, struct irqaction *action) { } +static inline void +irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) { } +#endif diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index fa564e8db996..0a9104b4608b 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1200,6 +1200,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) new->irq = irq; *old_ptr = new; + irq_pm_install_action(desc, new); + /* Reset broken irq detection when installing new handler */ desc->irq_count = 0; desc->irqs_unhandled = 0; @@ -1318,6 +1320,8 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) /* Found it - now remove it from the list of entries: */ *action_ptr = action->next; + irq_pm_remove_action(desc, action); + /* If this was the last handler, shut down the IRQ line: */ if (!desc->action) { irq_shutdown(desc); diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index b84141dcee5e..1b1b67a73218 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -13,6 +13,42 @@ #include "internals.h" +/* + * Called from __setup_irq() with desc->lock held after @action has + * been installed in the action chain. + */ +void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action) +{ + desc->nr_actions++; + + if (action->flags & IRQF_FORCE_RESUME) + desc->force_resume_depth++; + + WARN_ON_ONCE(desc->force_resume_depth && + desc->force_resume_depth != desc->nr_actions); + + if (action->flags & IRQF_NO_SUSPEND) + desc->no_suspend_depth++; + + WARN_ON_ONCE(desc->no_suspend_depth && + desc->no_suspend_depth != desc->nr_actions); +} + +/* + * Called from __free_irq() with desc->lock held after @action has + * been removed from the action chain. + */ +void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) +{ + desc->nr_actions--; + + if (action->flags & IRQF_FORCE_RESUME) + desc->force_resume_depth--; + + if (action->flags & IRQF_NO_SUSPEND) + desc->no_suspend_depth--; +} + static void suspend_device_irq(struct irq_desc *desc, int irq) { if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND)) -- GitLab From 5417de222393164b87b2d142b6ec332be40a2564 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 28 Aug 2014 15:48:59 +0200 Subject: [PATCH 0809/5088] genirq: Make use of pm misfeature accounting Use the accounting fields which got introduced for snity checking for the various PM options. Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- kernel/irq/pm.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index 1b1b67a73218..74ca6bb541d5 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -51,7 +51,7 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) static void suspend_device_irq(struct irq_desc *desc, int irq) { - if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND)) + if (!desc->action || desc->no_suspend_depth) return; desc->istate |= IRQS_SUSPENDED; @@ -94,11 +94,8 @@ static void resume_irq(struct irq_desc *desc, int irq) if (desc->istate & IRQS_SUSPENDED) goto resume; - if (!desc->action) - return; - - /* Interrupts marked with that flag are force reenabled */ - if (!(desc->action->flags & IRQF_FORCE_RESUME)) + /* Force resume the interrupt? */ + if (!desc->force_resume_depth) return; /* Pretend that it got disabled ! */ -- GitLab From 092fadd59b50208f6859f89dd7ea84e03955b544 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 28 Aug 2014 16:49:43 +0200 Subject: [PATCH 0810/5088] genirq: Move MASK_ON_SUSPEND handling into suspend_device_irqs() There is no reason why we should delay the masking of interrupts whose interrupt chip requests MASK_ON_SUSPEND to the point where we check the wakeup interrupts. We can do it right at the point where we mark the interrupt as suspended. Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- kernel/irq/pm.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index 74ca6bb541d5..a21b3dc9825a 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -56,6 +56,15 @@ static void suspend_device_irq(struct irq_desc *desc, int irq) desc->istate |= IRQS_SUSPENDED; __disable_irq(desc, irq); + + /* + * Hardware which has no wakeup source configuration facility + * requires that the non wakeup interrupts are masked at the + * chip level. The chip implementation indicates that with + * IRQCHIP_MASK_ON_SUSPEND. + */ + if (irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND) + mask_irq(desc); } /** @@ -176,19 +185,7 @@ int check_wakeup_irqs(void) if (irqd_is_wakeup_set(&desc->irq_data)) { if (desc->depth == 1 && desc->istate & IRQS_PENDING) return -EBUSY; - continue; } - /* - * Check the non wakeup interrupts whether they need - * to be masked before finally going into suspend - * state. That's for hardware which has no wakeup - * source configuration facility. The chip - * implementation indicates that with - * IRQCHIP_MASK_ON_SUSPEND. - */ - if (desc->istate & IRQS_SUSPENDED && - irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND) - mask_irq(desc); } return 0; -- GitLab From c4df606c40c3ac8ba76ad11fdbb10139f7fbb261 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 28 Aug 2014 22:50:43 +0200 Subject: [PATCH 0811/5088] genirq: Avoid double loop on suspend We can synchronize the suspended interrupts right away. No need for an extra loop. Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- kernel/irq/pm.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index a21b3dc9825a..cf0ce0163db9 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -49,10 +49,10 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) desc->no_suspend_depth--; } -static void suspend_device_irq(struct irq_desc *desc, int irq) +static bool suspend_device_irq(struct irq_desc *desc, int irq) { if (!desc->action || desc->no_suspend_depth) - return; + return false; desc->istate |= IRQS_SUSPENDED; __disable_irq(desc, irq); @@ -65,6 +65,7 @@ static void suspend_device_irq(struct irq_desc *desc, int irq) */ if (irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND) mask_irq(desc); + return true; } /** @@ -86,15 +87,15 @@ void suspend_device_irqs(void) for_each_irq_desc(irq, desc) { unsigned long flags; + bool sync; raw_spin_lock_irqsave(&desc->lock, flags); - suspend_device_irq(desc, irq); + sync = suspend_device_irq(desc, irq); raw_spin_unlock_irqrestore(&desc->lock, flags); - } - for_each_irq_desc(irq, desc) - if (desc->istate & IRQS_SUSPENDED) + if (sync) synchronize_irq(irq); + } } EXPORT_SYMBOL_GPL(suspend_device_irqs); -- GitLab From c3d7acd0273edf0ee50ccf85167acd7ae0759eda Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 Aug 2014 13:46:08 +0200 Subject: [PATCH 0812/5088] genirq: Distangle edge handler entry If the interrupt is disabled or has no action, then we should not call the poll check. Separate the checks. Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- kernel/irq/chip.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index a2b28a2fd7b1..f10c2e58a786 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -540,19 +540,29 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) raw_spin_lock(&desc->lock); desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); + /* - * If we're currently running this IRQ, or its disabled, - * we shouldn't process the IRQ. Mark it pending, handle - * the necessary masking and go out + * If the handler is currently running, mark it pending, + * handle the necessary masking and go out */ - if (unlikely(irqd_irq_disabled(&desc->irq_data) || - irqd_irq_inprogress(&desc->irq_data) || !desc->action)) { + if (unlikely(irqd_irq_inprogress(&desc->irq_data))) { if (!irq_check_poll(desc)) { desc->istate |= IRQS_PENDING; mask_ack_irq(desc); goto out_unlock; } } + + /* + * If its disabled or no action available then mask it and get + * out of here. + */ + if (irqd_irq_disabled(&desc->irq_data) || !desc->action) { + desc->istate |= IRQS_PENDING; + mask_ack_irq(desc); + goto out_unlock; + } + kstat_incr_irqs_this_cpu(irq, desc); /* Start handling the irq */ @@ -601,18 +611,27 @@ void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc) raw_spin_lock(&desc->lock); desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); + /* - * If we're currently running this IRQ, or its disabled, - * we shouldn't process the IRQ. Mark it pending, handle - * the necessary masking and go out + * If the handler is currently running, mark it pending, + * handle the necessary masking and go out */ - if (unlikely(irqd_irq_disabled(&desc->irq_data) || - irqd_irq_inprogress(&desc->irq_data) || !desc->action)) { + if (unlikely(irqd_irq_inprogress(&desc->irq_data))) { if (!irq_check_poll(desc)) { desc->istate |= IRQS_PENDING; goto out_eoi; } } + + /* + * If its disabled or no action available then mask it and get + * out of here. + */ + if (irqd_irq_disabled(&desc->irq_data) || !desc->action) { + desc->istate |= IRQS_PENDING; + goto out_eoi; + } + kstat_incr_irqs_this_cpu(irq, desc); do { -- GitLab From c7bd3ec0531aa636ad57ed9f27e637cbd247e64a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 Aug 2014 13:39:37 +0200 Subject: [PATCH 0813/5088] genirq: Create helper for flow handler entry check All flow handlers - except the per cpu ones - check for an interrupt in progress and an eventual concurrent polling on another cpu. Create a helper function for the repeated code pattern. Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- kernel/irq/chip.c | 48 ++++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index f10c2e58a786..6baf86085571 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -342,6 +342,13 @@ static bool irq_check_poll(struct irq_desc *desc) return irq_wait_for_poll(desc); } +static bool irq_may_run(struct irq_desc *desc) +{ + if (!irqd_irq_inprogress(&desc->irq_data)) + return true; + return irq_check_poll(desc); +} + /** * handle_simple_irq - Simple and software-decoded IRQs. * @irq: the interrupt number @@ -359,9 +366,8 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc) { raw_spin_lock(&desc->lock); - if (unlikely(irqd_irq_inprogress(&desc->irq_data))) - if (!irq_check_poll(desc)) - goto out_unlock; + if (!irq_may_run(desc)) + goto out_unlock; desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); kstat_incr_irqs_this_cpu(irq, desc); @@ -412,9 +418,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) raw_spin_lock(&desc->lock); mask_ack_irq(desc); - if (unlikely(irqd_irq_inprogress(&desc->irq_data))) - if (!irq_check_poll(desc)) - goto out_unlock; + if (!irq_may_run(desc)) + goto out_unlock; desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); kstat_incr_irqs_this_cpu(irq, desc); @@ -485,9 +490,8 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) raw_spin_lock(&desc->lock); - if (unlikely(irqd_irq_inprogress(&desc->irq_data))) - if (!irq_check_poll(desc)) - goto out; + if (!irq_may_run(desc)) + goto out; desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); kstat_incr_irqs_this_cpu(irq, desc); @@ -541,16 +545,10 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - /* - * If the handler is currently running, mark it pending, - * handle the necessary masking and go out - */ - if (unlikely(irqd_irq_inprogress(&desc->irq_data))) { - if (!irq_check_poll(desc)) { - desc->istate |= IRQS_PENDING; - mask_ack_irq(desc); - goto out_unlock; - } + if (!irq_may_run(desc)) { + desc->istate |= IRQS_PENDING; + mask_ack_irq(desc); + goto out_unlock; } /* @@ -612,15 +610,9 @@ void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc) desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - /* - * If the handler is currently running, mark it pending, - * handle the necessary masking and go out - */ - if (unlikely(irqd_irq_inprogress(&desc->irq_data))) { - if (!irq_check_poll(desc)) { - desc->istate |= IRQS_PENDING; - goto out_eoi; - } + if (!irq_may_run(desc)) { + desc->istate |= IRQS_PENDING; + goto out_eoi; } /* -- GitLab From b76f16748fa61801b1a1fd3ffb6f25ee228a35e0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 Aug 2014 13:54:09 +0200 Subject: [PATCH 0814/5088] genirq: Mark wakeup sources as armed on suspend This allows us to utilize this information in the irq_may_run() check without adding another conditional to the fast path. Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- include/linux/irq.h | 8 ++++++++ kernel/irq/pm.c | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/include/linux/irq.h b/include/linux/irq.h index 62af59242ddc..03f48d936f66 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -173,6 +173,7 @@ struct irq_data { * IRQD_IRQ_DISABLED - Disabled state of the interrupt * IRQD_IRQ_MASKED - Masked state of the interrupt * IRQD_IRQ_INPROGRESS - In progress state of the interrupt + * IRQD_WAKEUP_ARMED - Wakeup mode armed */ enum { IRQD_TRIGGER_MASK = 0xf, @@ -186,6 +187,7 @@ enum { IRQD_IRQ_DISABLED = (1 << 16), IRQD_IRQ_MASKED = (1 << 17), IRQD_IRQ_INPROGRESS = (1 << 18), + IRQD_WAKEUP_ARMED = (1 << 19), }; static inline bool irqd_is_setaffinity_pending(struct irq_data *d) @@ -257,6 +259,12 @@ static inline bool irqd_irq_inprogress(struct irq_data *d) return d->state_use_accessors & IRQD_IRQ_INPROGRESS; } +static inline bool irqd_is_wakeup_armed(struct irq_data *d) +{ + return d->state_use_accessors & IRQD_WAKEUP_ARMED; +} + + /* * Functions for chained handlers which can be enabled/disabled by the * standard disable_irq/enable_irq calls. Must be called with diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index cf0ce0163db9..766930eaeed9 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -54,6 +54,9 @@ static bool suspend_device_irq(struct irq_desc *desc, int irq) if (!desc->action || desc->no_suspend_depth) return false; + if (irqd_is_wakeup_set(&desc->irq_data)) + irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED); + desc->istate |= IRQS_SUSPENDED; __disable_irq(desc, irq); @@ -101,6 +104,8 @@ EXPORT_SYMBOL_GPL(suspend_device_irqs); static void resume_irq(struct irq_desc *desc, int irq) { + irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED); + if (desc->istate & IRQS_SUSPENDED) goto resume; -- GitLab From 9ce7a25849e80cfb264f4995f832b932c1987e1a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 Aug 2014 14:00:16 +0200 Subject: [PATCH 0815/5088] genirq: Simplify wakeup mechanism Currently we suspend wakeup interrupts by lazy disabling them and check later whether the interrupt has fired, but that's not sufficient for suspend to idle as there is no way to check that once we transitioned into the CPU idle state. So we change the mechanism in the following way: 1) Leave the wakeup interrupts enabled across suspend 2) Add a check to irq_may_run() which is called at the beginning of each flow handler whether the interrupt is an armed wakeup source. This check is basically free as it just extends the existing check for IRQD_IRQ_INPROGRESS. So no new conditional in the hot path. If the IRQD_WAKEUP_ARMED flag is set, then the interrupt is disabled, marked as pending/suspended and the pm core is notified about the wakeup event. Signed-off-by: Thomas Gleixner [ rjw: syscore.c and put irq_pm_check_wakeup() into pm.c ] Signed-off-by: Rafael J. Wysocki --- drivers/base/syscore.c | 7 +++-- include/linux/interrupt.h | 5 ---- kernel/irq/chip.c | 20 +++++++++++++- kernel/irq/internals.h | 2 ++ kernel/irq/pm.c | 55 +++++++++++++++++++++------------------ 5 files changed, 53 insertions(+), 36 deletions(-) diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c index dbb8350ea8dc..8d98a329f6ea 100644 --- a/drivers/base/syscore.c +++ b/drivers/base/syscore.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include static LIST_HEAD(syscore_ops_list); @@ -54,9 +54,8 @@ int syscore_suspend(void) pr_debug("Checking wakeup interrupts\n"); /* Return error code if there are any wakeup interrupts pending. */ - ret = check_wakeup_irqs(); - if (ret) - return ret; + if (pm_wakeup_pending()) + return -EBUSY; WARN_ONCE(!irqs_disabled(), "Interrupts enabled before system core suspend.\n"); diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 698ad053d064..69517a24bc50 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -193,11 +193,6 @@ extern void irq_wake_thread(unsigned int irq, void *dev_id); /* The following three functions are for the core kernel use only. */ extern void suspend_device_irqs(void); extern void resume_device_irqs(void); -#ifdef CONFIG_PM_SLEEP -extern int check_wakeup_irqs(void); -#else -static inline int check_wakeup_irqs(void) { return 0; } -#endif /** * struct irq_affinity_notify - context for notification of IRQ affinity changes diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 6baf86085571..e7917ff8a486 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -344,8 +344,26 @@ static bool irq_check_poll(struct irq_desc *desc) static bool irq_may_run(struct irq_desc *desc) { - if (!irqd_irq_inprogress(&desc->irq_data)) + unsigned int mask = IRQD_IRQ_INPROGRESS | IRQD_WAKEUP_ARMED; + + /* + * If the interrupt is not in progress and is not an armed + * wakeup interrupt, proceed. + */ + if (!irqd_has_set(&desc->irq_data, mask)) return true; + + /* + * If the interrupt is an armed wakeup source, mark it pending + * and suspended, disable it and notify the pm core about the + * event. + */ + if (irq_pm_check_wakeup(desc)) + return false; + + /* + * Handle a potential concurrent poll on a different core. + */ return irq_check_poll(desc); } diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index c402502a5111..4332d766619d 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -196,9 +196,11 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *d } #ifdef CONFIG_PM_SLEEP +bool irq_pm_check_wakeup(struct irq_desc *desc); void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action); void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action); #else +static inline bool irq_pm_check_wakeup(struct irq_desc *desc) { return false; } static inline void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action) { } static inline void diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index 766930eaeed9..3ca532592704 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -9,10 +9,24 @@ #include #include #include +#include #include #include "internals.h" +bool irq_pm_check_wakeup(struct irq_desc *desc) +{ + if (irqd_is_wakeup_armed(&desc->irq_data)) { + irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED); + desc->istate |= IRQS_SUSPENDED | IRQS_PENDING; + desc->depth++; + irq_disable(desc); + pm_system_wakeup(); + return true; + } + return false; +} + /* * Called from __setup_irq() with desc->lock held after @action has * been installed in the action chain. @@ -54,8 +68,16 @@ static bool suspend_device_irq(struct irq_desc *desc, int irq) if (!desc->action || desc->no_suspend_depth) return false; - if (irqd_is_wakeup_set(&desc->irq_data)) + if (irqd_is_wakeup_set(&desc->irq_data)) { irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED); + /* + * We return true here to force the caller to issue + * synchronize_irq(). We need to make sure that the + * IRQD_WAKEUP_ARMED is visible before we return from + * suspend_device_irqs(). + */ + return true; + } desc->istate |= IRQS_SUSPENDED; __disable_irq(desc, irq); @@ -79,9 +101,13 @@ static bool suspend_device_irq(struct irq_desc *desc, int irq) * for this purpose. * * So we disable all interrupts and mark them IRQS_SUSPENDED except - * for those which are unused and those which are marked as not + * for those which are unused, those which are marked as not * suspendable via an interrupt request with the flag IRQF_NO_SUSPEND - * set. + * set and those which are marked as active wakeup sources. + * + * The active wakeup sources are handled by the flow handler entry + * code which checks for the IRQD_WAKEUP_ARMED flag, suspends the + * interrupt and notifies the pm core about the wakeup. */ void suspend_device_irqs(void) { @@ -173,26 +199,3 @@ void resume_device_irqs(void) resume_irqs(false); } EXPORT_SYMBOL_GPL(resume_device_irqs); - -/** - * check_wakeup_irqs - check if any wake-up interrupts are pending - */ -int check_wakeup_irqs(void) -{ - struct irq_desc *desc; - int irq; - - for_each_irq_desc(irq, desc) { - /* - * Only interrupts which are marked as wakeup source - * and have not been disabled before the suspend check - * can abort suspend. - */ - if (irqd_is_wakeup_set(&desc->irq_data)) { - if (desc->depth == 1 && desc->istate & IRQS_PENDING) - return -EBUSY; - } - } - - return 0; -} -- GitLab From 5613570b133a294355d35fa66162afe7607a8abb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Sep 2014 13:49:07 +0200 Subject: [PATCH 0816/5088] x86 / PM: Set IRQCHIP_SKIP_SET_WAKE for IOAPIC IRQ chip objects Set the IRQCHIP_SKIP_SET_WAKE for IOAPIC IRQ chip objects so that interrupts from them can work as wakeup interrupts for suspend-to-idle. After this change, running enable_irq_wake() on one of the IRQs in question will succeed and IRQD_WAKEUP_STATE will be set for it, so all of the suspend-to-idle wakeup mechanics introduced previously will work for it automatically. Signed-off-by: Rafael J. Wysocki --- arch/x86/kernel/apic/io_apic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 337ce5a9b15c..1183d545da1e 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2623,6 +2623,7 @@ static struct irq_chip ioapic_chip __read_mostly = { .irq_eoi = ack_apic_level, .irq_set_affinity = native_ioapic_set_affinity, .irq_retrigger = ioapic_retrigger_irq, + .flags = IRQCHIP_SKIP_SET_WAKE, }; static inline void init_IO_APIC_traps(void) @@ -3173,6 +3174,7 @@ static struct irq_chip msi_chip = { .irq_ack = ack_apic_edge, .irq_set_affinity = msi_set_affinity, .irq_retrigger = ioapic_retrigger_irq, + .flags = IRQCHIP_SKIP_SET_WAKE, }; int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, @@ -3271,6 +3273,7 @@ static struct irq_chip dmar_msi_type = { .irq_ack = ack_apic_edge, .irq_set_affinity = dmar_msi_set_affinity, .irq_retrigger = ioapic_retrigger_irq, + .flags = IRQCHIP_SKIP_SET_WAKE, }; int arch_setup_dmar_msi(unsigned int irq) @@ -3321,6 +3324,7 @@ static struct irq_chip hpet_msi_type = { .irq_ack = ack_apic_edge, .irq_set_affinity = hpet_msi_set_affinity, .irq_retrigger = ioapic_retrigger_irq, + .flags = IRQCHIP_SKIP_SET_WAKE, }; int default_setup_hpet_msi(unsigned int irq, unsigned int id) @@ -3384,6 +3388,7 @@ static struct irq_chip ht_irq_chip = { .irq_ack = ack_apic_edge, .irq_set_affinity = ht_set_affinity, .irq_retrigger = ioapic_retrigger_irq, + .flags = IRQCHIP_SKIP_SET_WAKE, }; int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) -- GitLab From 76cde7e495904064d612cf3eb4bf6d9e76ff8191 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Sep 2014 13:49:16 +0200 Subject: [PATCH 0817/5088] PCI / PM: Make PCIe PME interrupts wake up from suspend-to-idle To make PCIe PME interrupts wake up the system from suspend to idle, make the PME driver use enable_irq_wake() on the IRQ during system suspend (if there are any wakeup devices below the given PCIe port) without disabling PME interrupts. This way, an interrupt will still trigger if a wakeup event happens and the system will be woken up (or system suspend in progress will be aborted) by means of the new mechanics introduced previously. This change allows Wake-on-LAN to be used for wakeup from suspend-to-idle on my MSI Wind tesbed netbook. Signed-off-by: Rafael J. Wysocki --- drivers/pci/pcie/pme.c | 61 +++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 82e06a86cd77..a9f9c46e5022 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -41,11 +41,17 @@ static int __init pcie_pme_setup(char *str) } __setup("pcie_pme=", pcie_pme_setup); +enum pme_suspend_level { + PME_SUSPEND_NONE = 0, + PME_SUSPEND_WAKEUP, + PME_SUSPEND_NOIRQ, +}; + struct pcie_pme_service_data { spinlock_t lock; struct pcie_device *srv; struct work_struct work; - bool noirq; /* Don't enable the PME interrupt used by this service. */ + enum pme_suspend_level suspend_level; }; /** @@ -223,7 +229,7 @@ static void pcie_pme_work_fn(struct work_struct *work) spin_lock_irq(&data->lock); for (;;) { - if (data->noirq) + if (data->suspend_level != PME_SUSPEND_NONE) break; pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta); @@ -250,7 +256,7 @@ static void pcie_pme_work_fn(struct work_struct *work) spin_lock_irq(&data->lock); } - if (!data->noirq) + if (data->suspend_level == PME_SUSPEND_NONE) pcie_pme_interrupt_enable(port, true); spin_unlock_irq(&data->lock); @@ -367,6 +373,21 @@ static int pcie_pme_probe(struct pcie_device *srv) return ret; } +static bool pcie_pme_check_wakeup(struct pci_bus *bus) +{ + struct pci_dev *dev; + + if (!bus) + return false; + + list_for_each_entry(dev, &bus->devices, bus_list) + if (device_may_wakeup(&dev->dev) + || pcie_pme_check_wakeup(dev->subordinate)) + return true; + + return false; +} + /** * pcie_pme_suspend - Suspend PCIe PME service device. * @srv: PCIe service device to suspend. @@ -375,11 +396,26 @@ static int pcie_pme_suspend(struct pcie_device *srv) { struct pcie_pme_service_data *data = get_service_data(srv); struct pci_dev *port = srv->port; + bool wakeup; + if (device_may_wakeup(&port->dev)) { + wakeup = true; + } else { + down_read(&pci_bus_sem); + wakeup = pcie_pme_check_wakeup(port->subordinate); + up_read(&pci_bus_sem); + } spin_lock_irq(&data->lock); - pcie_pme_interrupt_enable(port, false); - pcie_clear_root_pme_status(port); - data->noirq = true; + if (wakeup) { + enable_irq_wake(srv->irq); + data->suspend_level = PME_SUSPEND_WAKEUP; + } else { + struct pci_dev *port = srv->port; + + pcie_pme_interrupt_enable(port, false); + pcie_clear_root_pme_status(port); + data->suspend_level = PME_SUSPEND_NOIRQ; + } spin_unlock_irq(&data->lock); synchronize_irq(srv->irq); @@ -394,12 +430,17 @@ static int pcie_pme_suspend(struct pcie_device *srv) static int pcie_pme_resume(struct pcie_device *srv) { struct pcie_pme_service_data *data = get_service_data(srv); - struct pci_dev *port = srv->port; spin_lock_irq(&data->lock); - data->noirq = false; - pcie_clear_root_pme_status(port); - pcie_pme_interrupt_enable(port, true); + if (data->suspend_level == PME_SUSPEND_NOIRQ) { + struct pci_dev *port = srv->port; + + pcie_clear_root_pme_status(port); + pcie_pme_interrupt_enable(port, true); + } else { + disable_irq_wake(srv->irq); + } + data->suspend_level = PME_SUSPEND_NONE; spin_unlock_irq(&data->lock); return 0; -- GitLab From 27f3d18630cd7fbb03b62bd78a74303cb8c88069 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Sep 2014 14:14:17 +0200 Subject: [PATCH 0818/5088] PM / genirq: Document rules related to system suspend and interrupts Add a document describing how IRQs are managed during system suspend and resume, how wakeup interrupts work and what the IRQF_NO_SUSPEND flag is supposed to be used for. Signed-off-by: Rafael J. Wysocki --- .../power/suspend-and-interrupts.txt | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 Documentation/power/suspend-and-interrupts.txt diff --git a/Documentation/power/suspend-and-interrupts.txt b/Documentation/power/suspend-and-interrupts.txt new file mode 100644 index 000000000000..69663640dea5 --- /dev/null +++ b/Documentation/power/suspend-and-interrupts.txt @@ -0,0 +1,123 @@ +System Suspend and Device Interrupts + +Copyright (C) 2014 Intel Corp. +Author: Rafael J. Wysocki + + +Suspending and Resuming Device IRQs +----------------------------------- + +Device interrupt request lines (IRQs) are generally disabled during system +suspend after the "late" phase of suspending devices (that is, after all of the +->prepare, ->suspend and ->suspend_late callbacks have been executed for all +devices). That is done by suspend_device_irqs(). + +The rationale for doing so is that after the "late" phase of device suspend +there is no legitimate reason why any interrupts from suspended devices should +trigger and if any devices have not been suspended properly yet, it is better to +block interrupts from them anyway. Also, in the past we had problems with +interrupt handlers for shared IRQs that device drivers implementing them were +not prepared for interrupts triggering after their devices had been suspended. +In some cases they would attempt to access, for example, memory address spaces +of suspended devices and cause unpredictable behavior to ensue as a result. +Unfortunately, such problems are very difficult to debug and the introduction +of suspend_device_irqs(), along with the "noirq" phase of device suspend and +resume, was the only practical way to mitigate them. + +Device IRQs are re-enabled during system resume, right before the "early" phase +of resuming devices (that is, before starting to execute ->resume_early +callbacks for devices). The function doing that is resume_device_irqs(). + + +The IRQF_NO_SUSPEND Flag +------------------------ + +There are interrupts that can legitimately trigger during the entire system +suspend-resume cycle, including the "noirq" phases of suspending and resuming +devices as well as during the time when nonboot CPUs are taken offline and +brought back online. That applies to timer interrupts in the first place, +but also to IPIs and to some other special-purpose interrupts. + +The IRQF_NO_SUSPEND flag is used to indicate that to the IRQ subsystem when +requesting a special-purpose interrupt. It causes suspend_device_irqs() to +leave the corresponding IRQ enabled so as to allow the interrupt to work all +the time as expected. + +Note that the IRQF_NO_SUSPEND flag affects the entire IRQ and not just one +user of it. Thus, if the IRQ is shared, all of the interrupt handlers installed +for it will be executed as usual after suspend_device_irqs(), even if the +IRQF_NO_SUSPEND flag was not passed to request_irq() (or equivalent) by some of +the IRQ's users. For this reason, using IRQF_NO_SUSPEND and IRQF_SHARED at the +same time should be avoided. + + +System Wakeup Interrupts, enable_irq_wake() and disable_irq_wake() +------------------------------------------------------------------ + +System wakeup interrupts generally need to be configured to wake up the system +from sleep states, especially if they are used for different purposes (e.g. as +I/O interrupts) in the working state. + +That may involve turning on a special signal handling logic within the platform +(such as an SoC) so that signals from a given line are routed in a different way +during system sleep so as to trigger a system wakeup when needed. For example, +the platform may include a dedicated interrupt controller used specifically for +handling system wakeup events. Then, if a given interrupt line is supposed to +wake up the system from sleep sates, the corresponding input of that interrupt +controller needs to be enabled to receive signals from the line in question. +After wakeup, it generally is better to disable that input to prevent the +dedicated controller from triggering interrupts unnecessarily. + +The IRQ subsystem provides two helper functions to be used by device drivers for +those purposes. Namely, enable_irq_wake() turns on the platform's logic for +handling the given IRQ as a system wakeup interrupt line and disable_irq_wake() +turns that logic off. + +Calling enable_irq_wake() causes suspend_device_irqs() to treat the given IRQ +in a special way. Namely, the IRQ remains enabled, by on the first interrupt +it will be disabled, marked as pending and "suspended" so that it will be +re-enabled by resume_device_irqs() during the subsequent system resume. Also +the PM core is notified about the event which casues the system suspend in +progress to be aborted (that doesn't have to happen immediately, but at one +of the points where the suspend thread looks for pending wakeup events). + +This way every interrupt from a wakeup interrupt source will either cause the +system suspend currently in progress to be aborted or wake up the system if +already suspended. However, after suspend_device_irqs() interrupt handlers are +not executed for system wakeup IRQs. They are only executed for IRQF_NO_SUSPEND +IRQs at that time, but those IRQs should not be configured for system wakeup +using enable_irq_wake(). + + +Interrupts and Suspend-to-Idle +------------------------------ + +Suspend-to-idle (also known as the "freeze" sleep state) is a relatively new +system sleep state that works by idling all of the processors and waiting for +interrupts right after the "noirq" phase of suspending devices. + +Of course, this means that all of the interrupts with the IRQF_NO_SUSPEND flag +set will bring CPUs out of idle while in that state, but they will not cause the +IRQ subsystem to trigger a system wakeup. + +System wakeup interrupts, in turn, will trigger wakeup from suspend-to-idle in +analogy with what they do in the full system suspend case. The only difference +is that the wakeup from suspend-to-idle is signaled using the usual working +state interrupt delivery mechanisms and doesn't require the platform to use +any special interrupt handling logic for it to work. + + +IRQF_NO_SUSPEND and enable_irq_wake() +------------------------------------- + +There are no valid reasons to use both enable_irq_wake() and the IRQF_NO_SUSPEND +flag on the same IRQ. + +First of all, if the IRQ is not shared, the rules for handling IRQF_NO_SUSPEND +interrupts (interrupt handlers are invoked after suspend_device_irqs()) are +directly at odds with the rules for handling system wakeup interrupts (interrupt +handlers are not invoked after suspend_device_irqs()). + +Second, both enable_irq_wake() and IRQF_NO_SUSPEND apply to entire IRQs and not +to individual interrupt handlers, so sharing an IRQ between a system wakeup +interrupt source and an IRQF_NO_SUSPEND interrupt source does not make sense. -- GitLab From eadb0019d206591e34e864b62059b292e157d8fc Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Fri, 29 Aug 2014 15:12:12 +0800 Subject: [PATCH 0819/5088] ASoC: fsl-sai: using 'lsb-first' property instead of 'big-endian-data'. The 'big-endian-data' property is originally used to indicate whether the LSB firstly or MSB firstly will be transmitted to the CODEC or received from the CODEC, and there has nothing relation to the memory data. Generally, if the audio data in big endian format, which will be using the bytes reversion, Here this can only be used to bits reversion. So using the 'lsb-first' instead of 'big-endian-data' can make the code to be readable easier and more easy to understand what this property is used to do. This property used for configuring whether the LSB or the MSB is transmitted first for the fifo data. Signed-off-by: Xiubo Li Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl-sai.txt | 8 ++++---- sound/soc/fsl/fsl_sai.c | 6 +++--- sound/soc/fsl/fsl_sai.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 06a405e7f3e7..4956b14d4b06 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -20,9 +20,9 @@ Required properties: See ../pinctrl/pinctrl-bindings.txt for details of the property values. - big-endian: Boolean property, required if all the FTM_PWM registers are big-endian rather than little-endian. -- big-endian-data: If this property is absent, the little endian mode will - be in use as default, or the big endian mode will be in use for all the - fifo data. +- lsb-first: Configures whether the LSB or the MSB is transmitted first for + the fifo data. If this property is absent, the MSB is transmitted first as + default, or the LSB is transmitted first. - fsl,sai-synchronous-rx: This is a boolean property. If present, indicating that SAI will work in the synchronous mode (sync Tx with Rx) which means both the transimitter and receiver will send and receive data by following @@ -53,5 +53,5 @@ sai2: sai@40031000 { dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>, <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>; big-endian; - big-endian-data; + lsb-first; }; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index a6eb7849959c..7eeb1dd8ce27 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -175,7 +175,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, bool tx = fsl_dir == FSL_FMT_TRANSMITTER; u32 val_cr2 = 0, val_cr4 = 0; - if (!sai->big_endian_data) + if (!sai->is_lsb_first) val_cr4 |= FSL_SAI_CR4_MF; /* DAI mode */ @@ -304,7 +304,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, val_cr5 |= FSL_SAI_CR5_WNW(word_width); val_cr5 |= FSL_SAI_CR5_W0W(word_width); - if (sai->big_endian_data) + if (sai->is_lsb_first) val_cr5 |= FSL_SAI_CR5_FBT(0); else val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); @@ -573,7 +573,7 @@ static int fsl_sai_probe(struct platform_device *pdev) if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai")) sai->sai_on_imx = true; - sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); + sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 2cded440d567..34667209b607 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -132,7 +132,7 @@ struct fsl_sai { struct clk *bus_clk; struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; - bool big_endian_data; + bool is_lsb_first; bool is_dsp_mode; bool sai_on_imx; bool synchronous[2]; -- GitLab From ae70b190fce4a09a969dd69d0bd1c33441e24e60 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 25 Aug 2014 10:20:44 +0200 Subject: [PATCH 0820/5088] ASoC: ab8500-codec: Revert back to regmap Commit ff795d614bfa ("ASoC: ab8500: Convert register I/O to regmap") initially converted the ab8500 CODEC driver to use regmap rather than legacy ASoC IO. This was reverted though in commit 63e6d43bf80d ("ASoC: ab8500: Revert to using custom I/O functions") since the inital conversion was not working properly. This was presumebly because the SOC_SINGLE_XR_SX controls, which are used by this driver, did not properly support regmap at that point. This has since been fixed in commit 6137a5ca326d ("ASoC: Prepare SOC_SINGLE_XR_SX controls for regmap"). So revert back to regmap again. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 62 +++++++++++++++------------------ 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 62cf231f34cb..fd43827bb856 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -125,6 +125,8 @@ struct ab8500_codec_drvdata_dbg { /* Private data for AB8500 device-driver */ struct ab8500_codec_drvdata { + struct regmap *regmap; + /* Sidetone */ long *sid_fir_values; enum sid_state sid_status; @@ -165,49 +167,35 @@ static inline const char *amic_type_str(enum amic_type type) */ /* Read a register from the audio-bank of AB8500 */ -static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec, - unsigned int reg) +static int ab8500_codec_read_reg(void *context, unsigned int reg, + unsigned int *value) { + struct device *dev = context; int status; - unsigned int value = 0; u8 value8; - status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO, - reg, &value8); - if (status < 0) { - dev_err(codec->dev, - "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - } else { - dev_dbg(codec->dev, - "%s: Read 0x%02x from register 0x%02x:0x%02x\n", - __func__, value8, (u8)AB8500_AUDIO, (u8)reg); - value = (unsigned int)value8; - } + status = abx500_get_register_interruptible(dev, AB8500_AUDIO, + reg, &value8); + *value = (unsigned int)value8; - return value; + return status; } /* Write to a register in the audio-bank of AB8500 */ -static int ab8500_codec_write_reg(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) +static int ab8500_codec_write_reg(void *context, unsigned int reg, + unsigned int value) { - int status; - - status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO, - reg, value); - if (status < 0) - dev_err(codec->dev, - "%s: ERROR: Register (%02x:%02x) write failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - else - dev_dbg(codec->dev, - "%s: Wrote 0x%02x into register %02x:%02x\n", - __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg); + struct device *dev = context; - return status; + return abx500_set_register_interruptible(dev, AB8500_AUDIO, + reg, value); } +static const struct regmap_config ab8500_codec_regmap = { + .reg_read = ab8500_codec_read_reg, + .reg_write = ab8500_codec_write_reg, +}; + /* * Controls - DAPM */ @@ -2564,9 +2552,6 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver ab8500_codec_driver = { .probe = ab8500_codec_probe, - .read = ab8500_codec_read_reg, - .write = ab8500_codec_write_reg, - .reg_word_size = sizeof(u8), .controls = ab8500_ctrls, .num_controls = ARRAY_SIZE(ab8500_ctrls), .dapm_widgets = ab8500_dapm_widgets, @@ -2591,6 +2576,15 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) drvdata->anc_status = ANC_UNCONFIGURED; dev_set_drvdata(&pdev->dev, drvdata); + drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev, + &ab8500_codec_regmap); + if (IS_ERR(drvdata->regmap)) { + status = PTR_ERR(drvdata->regmap); + dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", + __func__, status); + return status; + } + dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__); status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver, ab8500_codec_dai, -- GitLab From 87e392164ab6c0f3f055f8483dc7dc3f1afa19ad Mon Sep 17 00:00:00 2001 From: Mike Turquette Date: Wed, 27 Aug 2014 15:36:37 -0700 Subject: [PATCH 0821/5088] clk: mvebu: share locks between gate clocks Refactor mvebu_clk_gating_setup() to use a common spinlock instead of a unique lock for every instance of a struct clk_gating_ctrl object. This will be used later for a separate mux clock type that shares a register with gate clock types and needs to use the same lock to protect access to the register. Cc: Andrew Lunn Tested-by: Andrew Lunn Signed-off-by: Mike Turquette --- drivers/clk/mvebu/common.c | 9 ++++++--- drivers/clk/mvebu/common.h | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c index 25ceccf939ad..8145c4efc381 100644 --- a/drivers/clk/mvebu/common.c +++ b/drivers/clk/mvebu/common.c @@ -89,8 +89,10 @@ void __init mvebu_coreclk_setup(struct device_node *np, * Clock Gating Control */ +DEFINE_SPINLOCK(ctrl_gating_lock); + struct clk_gating_ctrl { - spinlock_t lock; + spinlock_t *lock; struct clk **gates; int num_gates; }; @@ -138,7 +140,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np, if (WARN_ON(!ctrl)) goto ctrl_out; - spin_lock_init(&ctrl->lock); + /* lock must already be initialized */ + ctrl->lock = &ctrl_gating_lock; /* Count, allocate, and register clock gates */ for (n = 0; desc[n].name;) @@ -155,7 +158,7 @@ void __init mvebu_clk_gating_setup(struct device_node *np, (desc[n].parent) ? desc[n].parent : default_parent; ctrl->gates[n] = clk_register_gate(NULL, desc[n].name, parent, desc[n].flags, base, desc[n].bit_idx, - 0, &ctrl->lock); + 0, ctrl->lock); WARN_ON(IS_ERR(ctrl->gates[n])); } diff --git a/drivers/clk/mvebu/common.h b/drivers/clk/mvebu/common.h index f968b4d9df92..8cd28e47471c 100644 --- a/drivers/clk/mvebu/common.h +++ b/drivers/clk/mvebu/common.h @@ -17,6 +17,8 @@ #include +extern spinlock_t ctrl_gating_lock; + struct device_node; struct coreclk_ratio { -- GitLab From e8e8a9b0d86c093b208789fd71501c91a919ffdb Mon Sep 17 00:00:00 2001 From: Mike Turquette Date: Wed, 27 Aug 2014 17:11:38 -0700 Subject: [PATCH 0822/5088] clk: mvebu: powersave clock is a multiplexer Kirkwood is unique among the mvebu SoCs for having a clock multiplexer that feeds into the cpu. This multiplexer can select either the cpu pll or the ddr clock as its input signal, allowing for a choice between performance and power savings. This patch introduces the code needed to register the clock multiplexer on Kirkwood SoCs but does not include the clock data to actually register the clock. That will be done in a follow-up patch which is necessary to prevent breaking git bisect. Cc: Tomeu Vizoso Tested-by: Andrew Lunn Signed-off-by: Mike Turquette --- drivers/clk/mvebu/kirkwood.c | 87 ++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index ddb666a86500..f73a2fa8a561 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c @@ -13,9 +13,11 @@ */ #include +#include #include #include #include +#include #include "common.h" /* @@ -225,6 +227,91 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = { { } }; + +/* + * Clock Muxing Control + */ + +struct clk_muxing_soc_desc { + const char *name; + const char **parents; + int num_parents; + int shift; + int width; + unsigned long flags; +}; + +struct clk_muxing_ctrl { + spinlock_t *lock; + struct clk **muxes; + int num_muxes; +}; + +#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) + +static struct clk *clk_muxing_get_src( + struct of_phandle_args *clkspec, void *data) +{ + struct clk_muxing_ctrl *ctrl = (struct clk_muxing_ctrl *)data; + int n; + + if (clkspec->args_count < 1) + return ERR_PTR(-EINVAL); + + for (n = 0; n < ctrl->num_muxes; n++) { + struct clk_mux *mux = + to_clk_mux(__clk_get_hw(ctrl->muxes[n])); + if (clkspec->args[0] == mux->shift) + return ctrl->muxes[n]; + } + return ERR_PTR(-ENODEV); +} + +static void __init kirkwood_clk_muxing_setup(struct device_node *np, + const struct clk_muxing_soc_desc *desc) +{ + struct clk_muxing_ctrl *ctrl; + void __iomem *base; + int n; + + base = of_iomap(np, 0); + if (WARN_ON(!base)) + return; + + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (WARN_ON(!ctrl)) + goto ctrl_out; + + /* lock must already be initialized */ + ctrl->lock = &ctrl_gating_lock; + + /* Count, allocate, and register clock muxes */ + for (n = 0; desc[n].name;) + n++; + + ctrl->num_muxes = n; + ctrl->muxes = kcalloc(ctrl->num_muxes, sizeof(struct clk *), + GFP_KERNEL); + if (WARN_ON(!ctrl->muxes)) + goto muxes_out; + + for (n = 0; n < ctrl->num_muxes; n++) { + ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name, + desc[n].parents, desc[n].num_parents, + desc[n].flags, base, desc[n].shift, + desc[n].width, desc[n].flags, ctrl->lock); + WARN_ON(IS_ERR(ctrl->muxes[n])); + } + + of_clk_add_provider(np, clk_muxing_get_src, ctrl); + + return; +muxes_out: + kfree(ctrl); +ctrl_out: + iounmap(base); +} + static void __init kirkwood_clk_init(struct device_node *np) { struct device_node *cgnp = -- GitLab From b6c044a3d881c1b01fe0220ad76e548ea5d79b1c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 3 Aug 2014 10:36:59 +0800 Subject: [PATCH 0823/5088] gpu: ipu-v3: Select GENERIC_IRQ_CHIP to fix build error This driver uses GENERIC_IRQ_CHIP, so it needs to select GENERIC_IRQ_CHIP to avoid build error. Fixes below build errors: ERROR: "irq_alloc_domain_generic_chips" [drivers/gpu/ipu-v3/imx-ipu-v3.ko] undefined! ERROR: "irq_gc_mask_clr_bit" [drivers/gpu/ipu-v3/imx-ipu-v3.ko] undefined! ERROR: "irq_gc_mask_set_bit" [drivers/gpu/ipu-v3/imx-ipu-v3.ko] undefined! ERROR: "irq_generic_chip_ops" [drivers/gpu/ipu-v3/imx-ipu-v3.ko] undefined! ERROR: "irq_gc_ack_set_bit" [drivers/gpu/ipu-v3/imx-ipu-v3.ko] undefined! ERROR: "irq_get_domain_generic_chip" [drivers/gpu/ipu-v3/imx-ipu-v3.ko] undefined! make[1]: *** [__modpost] Error 1 make: *** [modules] Error 2 Signed-off-by: Axel Lin Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/ipu-v3/Kconfig b/drivers/gpu/ipu-v3/Kconfig index 2f228a2f2a48..01864a55264a 100644 --- a/drivers/gpu/ipu-v3/Kconfig +++ b/drivers/gpu/ipu-v3/Kconfig @@ -2,6 +2,7 @@ config IMX_IPUV3_CORE tristate "IPUv3 core support" depends on SOC_IMX5 || SOC_IMX6Q || SOC_IMX6SL || ARCH_MULTIPLATFORM depends on RESET_CONTROLLER + select GENERIC_IRQ_CHIP help Choose this if you have a i.MX5/6 system and want to use the Image Processing Unit. This option only enables IPU base support. -- GitLab From e4946cdcabcffd4814e153e71d28884b94c65e9e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 3 Aug 2014 10:38:18 +0800 Subject: [PATCH 0824/5088] gpu: ipu-v3: Return proper error on ipu_add_client_devices error path Avoid returning an uninitialized variable in the error path. Signed-off-by: Axel Lin Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 04e7b2eafbdd..e340bebd3419 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -1116,8 +1116,10 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base) id++, ®->pdata, sizeof(reg->pdata)); } - if (IS_ERR(pdev)) + if (IS_ERR(pdev)) { + ret = PTR_ERR(pdev); goto err_register; + } } return 0; -- GitLab From 0752e169ba523e35f70d2fee4d06680b33e0e202 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 2 Jun 2014 15:17:54 +0200 Subject: [PATCH 0825/5088] gpio: adnp: switch to use irqchip helpers This switches the ADNP GPIO driver to use the gpiolib irqchip helpers. Also do some random refactoring to make it look like most other GPIO drivers. Cc: Roland Stigge Cc: Lars Poeschel Cc: Thierry Reding Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-adnp.c | 155 ++++++++++++--------------------------- 2 files changed, 48 insertions(+), 108 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 1fe93eb61927..ec27ec0be8c2 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -690,6 +690,7 @@ config GPIO_ADP5588_IRQ config GPIO_ADNP tristate "Avionic Design N-bit GPIO expander" depends on I2C && OF_GPIO + select GPIOLIB_IRQCHIP help This option enables support for N GPIOs found on Avionic Design I2C GPIO expanders. The register space will be extended by powers diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 416b2200d4f1..d3d0a90fe542 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -6,10 +6,9 @@ * published by the Free Software Foundation. */ -#include +#include #include #include -#include #include #include #include @@ -27,8 +26,6 @@ struct adnp { unsigned int reg_shift; struct mutex i2c_lock; - - struct irq_domain *domain; struct mutex irq_lock; u8 *irq_enable; @@ -253,6 +250,7 @@ static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios) { struct gpio_chip *chip = &adnp->gpio; + int err; adnp->reg_shift = get_count_order(num_gpios) - 3; @@ -272,6 +270,10 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios) chip->of_node = chip->dev->of_node; chip->owner = THIS_MODULE; + err = gpiochip_add(chip); + if (err) + return err; + return 0; } @@ -326,7 +328,8 @@ static irqreturn_t adnp_irq(int irq, void *data) for_each_set_bit(bit, &pending, 8) { unsigned int child_irq; - child_irq = irq_find_mapping(adnp->domain, base + bit); + child_irq = irq_find_mapping(adnp->gpio.irqdomain, + base + bit); handle_nested_irq(child_irq); } } @@ -334,35 +337,32 @@ static irqreturn_t adnp_irq(int irq, void *data) return IRQ_HANDLED; } -static int adnp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct adnp *adnp = to_adnp(chip); - return irq_create_mapping(adnp->domain, offset); -} - -static void adnp_irq_mask(struct irq_data *data) +static void adnp_irq_mask(struct irq_data *d) { - struct adnp *adnp = irq_data_get_irq_chip_data(data); - unsigned int reg = data->hwirq >> adnp->reg_shift; - unsigned int pos = data->hwirq & 7; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adnp *adnp = to_adnp(gc); + unsigned int reg = d->hwirq >> adnp->reg_shift; + unsigned int pos = d->hwirq & 7; adnp->irq_enable[reg] &= ~BIT(pos); } -static void adnp_irq_unmask(struct irq_data *data) +static void adnp_irq_unmask(struct irq_data *d) { - struct adnp *adnp = irq_data_get_irq_chip_data(data); - unsigned int reg = data->hwirq >> adnp->reg_shift; - unsigned int pos = data->hwirq & 7; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adnp *adnp = to_adnp(gc); + unsigned int reg = d->hwirq >> adnp->reg_shift; + unsigned int pos = d->hwirq & 7; adnp->irq_enable[reg] |= BIT(pos); } -static int adnp_irq_set_type(struct irq_data *data, unsigned int type) +static int adnp_irq_set_type(struct irq_data *d, unsigned int type) { - struct adnp *adnp = irq_data_get_irq_chip_data(data); - unsigned int reg = data->hwirq >> adnp->reg_shift; - unsigned int pos = data->hwirq & 7; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adnp *adnp = to_adnp(gc); + unsigned int reg = d->hwirq >> adnp->reg_shift; + unsigned int pos = d->hwirq & 7; if (type & IRQ_TYPE_EDGE_RISING) adnp->irq_rise[reg] |= BIT(pos); @@ -387,16 +387,18 @@ static int adnp_irq_set_type(struct irq_data *data, unsigned int type) return 0; } -static void adnp_irq_bus_lock(struct irq_data *data) +static void adnp_irq_bus_lock(struct irq_data *d) { - struct adnp *adnp = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adnp *adnp = to_adnp(gc); mutex_lock(&adnp->irq_lock); } -static void adnp_irq_bus_unlock(struct irq_data *data) +static void adnp_irq_bus_unlock(struct irq_data *d) { - struct adnp *adnp = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adnp *adnp = to_adnp(gc); unsigned int num_regs = 1 << adnp->reg_shift, i; mutex_lock(&adnp->i2c_lock); @@ -408,26 +410,6 @@ static void adnp_irq_bus_unlock(struct irq_data *data) mutex_unlock(&adnp->irq_lock); } -static int adnp_irq_reqres(struct irq_data *data) -{ - struct adnp *adnp = irq_data_get_irq_chip_data(data); - - if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) { - dev_err(adnp->gpio.dev, - "unable to lock HW IRQ %lu for IRQ\n", - data->hwirq); - return -EINVAL; - } - return 0; -} - -static void adnp_irq_relres(struct irq_data *data) -{ - struct adnp *adnp = irq_data_get_irq_chip_data(data); - - gpio_unlock_as_irq(&adnp->gpio, data->hwirq); -} - static struct irq_chip adnp_irq_chip = { .name = "gpio-adnp", .irq_mask = adnp_irq_mask, @@ -435,29 +417,6 @@ static struct irq_chip adnp_irq_chip = { .irq_set_type = adnp_irq_set_type, .irq_bus_lock = adnp_irq_bus_lock, .irq_bus_sync_unlock = adnp_irq_bus_unlock, - .irq_request_resources = adnp_irq_reqres, - .irq_release_resources = adnp_irq_relres, -}; - -static int adnp_irq_map(struct irq_domain *domain, unsigned int irq, - irq_hw_number_t hwirq) -{ - irq_set_chip_data(irq, domain->host_data); - irq_set_chip(irq, &adnp_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; -} - -static const struct irq_domain_ops adnp_irq_domain_ops = { - .map = adnp_irq_map, - .xlate = irq_domain_xlate_twocell, }; static int adnp_irq_setup(struct adnp *adnp) @@ -503,35 +462,28 @@ static int adnp_irq_setup(struct adnp *adnp) adnp->irq_enable[i] = 0x00; } - adnp->domain = irq_domain_add_linear(chip->of_node, chip->ngpio, - &adnp_irq_domain_ops, adnp); - - err = request_threaded_irq(adnp->client->irq, NULL, adnp_irq, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - dev_name(chip->dev), adnp); + err = devm_request_threaded_irq(chip->dev, adnp->client->irq, + NULL, adnp_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + dev_name(chip->dev), adnp); if (err != 0) { dev_err(chip->dev, "can't request IRQ#%d: %d\n", adnp->client->irq, err); return err; } - chip->to_irq = adnp_gpio_to_irq; - return 0; -} - -static void adnp_irq_teardown(struct adnp *adnp) -{ - unsigned int irq, i; - - free_irq(adnp->client->irq, adnp); - - for (i = 0; i < adnp->gpio.ngpio; i++) { - irq = irq_find_mapping(adnp->domain, i); - if (irq > 0) - irq_dispose_mapping(irq); + err = gpiochip_irqchip_add(chip, + &adnp_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); + if (err) { + dev_err(chip->dev, + "could not connect irqchip to gpiochip\n"); + return err; } - irq_domain_remove(adnp->domain); + return 0; } static int adnp_i2c_probe(struct i2c_client *client, @@ -558,38 +510,25 @@ static int adnp_i2c_probe(struct i2c_client *client, adnp->client = client; err = adnp_gpio_setup(adnp, num_gpios); - if (err < 0) + if (err) return err; if (of_find_property(np, "interrupt-controller", NULL)) { err = adnp_irq_setup(adnp); - if (err < 0) - goto teardown; + if (err) + return err; } - err = gpiochip_add(&adnp->gpio); - if (err < 0) - goto teardown; - i2c_set_clientdata(client, adnp); - return 0; -teardown: - if (of_find_property(np, "interrupt-controller", NULL)) - adnp_irq_teardown(adnp); - - return err; + return 0; } static int adnp_i2c_remove(struct i2c_client *client) { struct adnp *adnp = i2c_get_clientdata(client); - struct device_node *np = client->dev.of_node; gpiochip_remove(&adnp->gpio); - if (of_find_property(np, "interrupt-controller", NULL)) - adnp_irq_teardown(adnp); - return 0; } -- GitLab From e68885e24ad1a2d7d4ad6df04cbc9b623bd1d0b9 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 2 Sep 2014 00:37:13 -0300 Subject: [PATCH 0826/5088] gpu: ipu-v3: ipu-smfc: Do not leave DEBUG defined Let's only define DEBUG for debugging purpose and not by default to avoid printing debugging message unnecessarily. Signed-off-by: Fabio Estevam Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-smfc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/ipu-v3/ipu-smfc.c b/drivers/gpu/ipu-v3/ipu-smfc.c index e4f85ad286fc..4939c5011d4d 100644 --- a/drivers/gpu/ipu-v3/ipu-smfc.c +++ b/drivers/gpu/ipu-v3/ipu-smfc.c @@ -8,7 +8,6 @@ * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ -#define DEBUG #include #include #include -- GitLab From 2ffd48f2e7ae06c3d7b2bcde9a0cb211d1a32468 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Tue, 19 Aug 2014 10:52:40 -0700 Subject: [PATCH 0827/5088] gpu: ipu-v3: Add Camera Sensor Interface unit Adds the Camera Sensor Interface (CSI) unit required for video capture. Signed-off-by: Steve Longerbeam Removed the unused clk_get_rate in ipu_csi_init_interface and the ipu_csi_ccir_err_detection_enable/disable functions. Checkpatch cleanup. Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/Makefile | 2 +- drivers/gpu/ipu-v3/ipu-common.c | 44 +- drivers/gpu/ipu-v3/ipu-csi.c | 741 ++++++++++++++++++++++++++++++++ drivers/gpu/ipu-v3/ipu-prv.h | 6 + include/video/imx-ipu-v3.h | 32 +- 5 files changed, 810 insertions(+), 15 deletions(-) create mode 100644 drivers/gpu/ipu-v3/ipu-csi.c diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile index 0b42836caae1..d22bd06caa6d 100644 --- a/drivers/gpu/ipu-v3/Makefile +++ b/drivers/gpu/ipu-v3/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o -imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-dc.o ipu-di.o \ +imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \ ipu-dp.o ipu-dmfc.o ipu-smfc.o diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index cae543115856..511c364231a2 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -217,18 +217,6 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask) } EXPORT_SYMBOL_GPL(ipu_module_disable); -int ipu_csi_enable(struct ipu_soc *ipu, int csi) -{ - return ipu_module_enable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN); -} -EXPORT_SYMBOL_GPL(ipu_csi_enable); - -int ipu_csi_disable(struct ipu_soc *ipu, int csi) -{ - return ipu_module_disable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN); -} -EXPORT_SYMBOL_GPL(ipu_csi_disable); - int ipu_smfc_enable(struct ipu_soc *ipu) { return ipu_module_enable(ipu, IPU_CONF_SMFC_EN); @@ -439,6 +427,8 @@ struct ipu_devtype { unsigned long cpmem_ofs; unsigned long srm_ofs; unsigned long tpm_ofs; + unsigned long csi0_ofs; + unsigned long csi1_ofs; unsigned long disp0_ofs; unsigned long disp1_ofs; unsigned long dc_tmpl_ofs; @@ -452,6 +442,8 @@ static struct ipu_devtype ipu_type_imx51 = { .cpmem_ofs = 0x1f000000, .srm_ofs = 0x1f040000, .tpm_ofs = 0x1f060000, + .csi0_ofs = 0x1f030000, + .csi1_ofs = 0x1f038000, .disp0_ofs = 0x1e040000, .disp1_ofs = 0x1e048000, .dc_tmpl_ofs = 0x1f080000, @@ -465,6 +457,8 @@ static struct ipu_devtype ipu_type_imx53 = { .cpmem_ofs = 0x07000000, .srm_ofs = 0x07040000, .tpm_ofs = 0x07060000, + .csi0_ofs = 0x07030000, + .csi1_ofs = 0x07038000, .disp0_ofs = 0x06040000, .disp1_ofs = 0x06048000, .dc_tmpl_ofs = 0x07080000, @@ -478,6 +472,8 @@ static struct ipu_devtype ipu_type_imx6q = { .cpmem_ofs = 0x00300000, .srm_ofs = 0x00340000, .tpm_ofs = 0x00360000, + .csi0_ofs = 0x00230000, + .csi1_ofs = 0x00238000, .disp0_ofs = 0x00240000, .disp1_ofs = 0x00248000, .dc_tmpl_ofs = 0x00380000, @@ -508,6 +504,20 @@ static int ipu_submodules_init(struct ipu_soc *ipu, goto err_cpmem; } + ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs, + IPU_CONF_CSI0_EN, ipu_clk); + if (ret) { + unit = "csi0"; + goto err_csi_0; + } + + ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs, + IPU_CONF_CSI1_EN, ipu_clk); + if (ret) { + unit = "csi1"; + goto err_csi_1; + } + ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, IPU_CONF_DI0_EN, ipu_clk); if (ret) { @@ -562,6 +572,10 @@ static int ipu_submodules_init(struct ipu_soc *ipu, err_di_1: ipu_di_exit(ipu, 0); err_di_0: + ipu_csi_exit(ipu, 1); +err_csi_1: + ipu_csi_exit(ipu, 0); +err_csi_0: ipu_cpmem_exit(ipu); err_cpmem: dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret); @@ -640,6 +654,8 @@ static void ipu_submodules_exit(struct ipu_soc *ipu) ipu_dc_exit(ipu); ipu_di_exit(ipu, 1); ipu_di_exit(ipu, 0); + ipu_csi_exit(ipu, 1); + ipu_csi_exit(ipu, 0); ipu_cpmem_exit(ipu); } @@ -859,6 +875,10 @@ static int ipu_probe(struct platform_device *pdev) ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS); dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n", ipu_base + devtype->cpmem_ofs); + dev_dbg(&pdev->dev, "csi0: 0x%08lx\n", + ipu_base + devtype->csi0_ofs); + dev_dbg(&pdev->dev, "csi1: 0x%08lx\n", + ipu_base + devtype->csi1_ofs); dev_dbg(&pdev->dev, "disp0: 0x%08lx\n", ipu_base + devtype->disp0_ofs); dev_dbg(&pdev->dev, "disp1: 0x%08lx\n", diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c new file mode 100644 index 000000000000..d6f56471bd2a --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -0,0 +1,741 @@ +/* + * Copyright (C) 2012-2014 Mentor Graphics Inc. + * Copyright (C) 2005-2009 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 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 +#include +#include +#include +#include + +#include "ipu-prv.h" + +struct ipu_csi { + void __iomem *base; + int id; + u32 module; + struct clk *clk_ipu; /* IPU bus clock */ + spinlock_t lock; + bool inuse; + struct ipu_soc *ipu; +}; + +/* CSI Register Offsets */ +#define CSI_SENS_CONF 0x0000 +#define CSI_SENS_FRM_SIZE 0x0004 +#define CSI_ACT_FRM_SIZE 0x0008 +#define CSI_OUT_FRM_CTRL 0x000c +#define CSI_TST_CTRL 0x0010 +#define CSI_CCIR_CODE_1 0x0014 +#define CSI_CCIR_CODE_2 0x0018 +#define CSI_CCIR_CODE_3 0x001c +#define CSI_MIPI_DI 0x0020 +#define CSI_SKIP 0x0024 +#define CSI_CPD_CTRL 0x0028 +#define CSI_CPD_RC(n) (0x002c + ((n)*4)) +#define CSI_CPD_RS(n) (0x004c + ((n)*4)) +#define CSI_CPD_GRC(n) (0x005c + ((n)*4)) +#define CSI_CPD_GRS(n) (0x007c + ((n)*4)) +#define CSI_CPD_GBC(n) (0x008c + ((n)*4)) +#define CSI_CPD_GBS(n) (0x00Ac + ((n)*4)) +#define CSI_CPD_BC(n) (0x00Bc + ((n)*4)) +#define CSI_CPD_BS(n) (0x00Dc + ((n)*4)) +#define CSI_CPD_OFFSET1 0x00ec +#define CSI_CPD_OFFSET2 0x00f0 + +/* CSI Register Fields */ +#define CSI_SENS_CONF_DATA_FMT_SHIFT 8 +#define CSI_SENS_CONF_DATA_FMT_MASK 0x00000700 +#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 0L +#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV 1L +#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L +#define CSI_SENS_CONF_DATA_FMT_BAYER 3L +#define CSI_SENS_CONF_DATA_FMT_RGB565 4L +#define CSI_SENS_CONF_DATA_FMT_RGB555 5L +#define CSI_SENS_CONF_DATA_FMT_RGB444 6L +#define CSI_SENS_CONF_DATA_FMT_JPEG 7L + +#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0 +#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1 +#define CSI_SENS_CONF_DATA_POL_SHIFT 2 +#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3 +#define CSI_SENS_CONF_SENS_PRTCL_MASK 0x00000070 +#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4 +#define CSI_SENS_CONF_PACK_TIGHT_SHIFT 7 +#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 11 +#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15 +#define CSI_SENS_CONF_DIVRATIO_SHIFT 16 + +#define CSI_SENS_CONF_DIVRATIO_MASK 0x00ff0000 +#define CSI_SENS_CONF_DATA_DEST_SHIFT 24 +#define CSI_SENS_CONF_DATA_DEST_MASK 0x07000000 +#define CSI_SENS_CONF_JPEG8_EN_SHIFT 27 +#define CSI_SENS_CONF_JPEG_EN_SHIFT 28 +#define CSI_SENS_CONF_FORCE_EOF_SHIFT 29 +#define CSI_SENS_CONF_DATA_EN_POL_SHIFT 31 + +#define CSI_DATA_DEST_IC 2 +#define CSI_DATA_DEST_IDMAC 4 + +#define CSI_CCIR_ERR_DET_EN 0x01000000 +#define CSI_HORI_DOWNSIZE_EN 0x80000000 +#define CSI_VERT_DOWNSIZE_EN 0x40000000 +#define CSI_TEST_GEN_MODE_EN 0x01000000 + +#define CSI_HSC_MASK 0x1fff0000 +#define CSI_HSC_SHIFT 16 +#define CSI_VSC_MASK 0x00000fff +#define CSI_VSC_SHIFT 0 + +#define CSI_TEST_GEN_R_MASK 0x000000ff +#define CSI_TEST_GEN_R_SHIFT 0 +#define CSI_TEST_GEN_G_MASK 0x0000ff00 +#define CSI_TEST_GEN_G_SHIFT 8 +#define CSI_TEST_GEN_B_MASK 0x00ff0000 +#define CSI_TEST_GEN_B_SHIFT 16 + +#define CSI_MAX_RATIO_SKIP_SMFC_MASK 0x00000007 +#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT 0 +#define CSI_SKIP_SMFC_MASK 0x000000f8 +#define CSI_SKIP_SMFC_SHIFT 3 +#define CSI_ID_2_SKIP_MASK 0x00000300 +#define CSI_ID_2_SKIP_SHIFT 8 + +#define CSI_COLOR_FIRST_ROW_MASK 0x00000002 +#define CSI_COLOR_FIRST_COMP_MASK 0x00000001 + +/* MIPI CSI-2 data types */ +#define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */ +#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */ +#define MIPI_DT_YUV422 0x1e /* UYVY... */ +#define MIPI_DT_RGB444 0x20 +#define MIPI_DT_RGB555 0x21 +#define MIPI_DT_RGB565 0x22 +#define MIPI_DT_RGB666 0x23 +#define MIPI_DT_RGB888 0x24 +#define MIPI_DT_RAW6 0x28 +#define MIPI_DT_RAW7 0x29 +#define MIPI_DT_RAW8 0x2a +#define MIPI_DT_RAW10 0x2b +#define MIPI_DT_RAW12 0x2c +#define MIPI_DT_RAW14 0x2d + +/* + * Bitfield of CSI bus signal polarities and modes. + */ +struct ipu_csi_bus_config { + unsigned data_width:4; + unsigned clk_mode:3; + unsigned ext_vsync:1; + unsigned vsync_pol:1; + unsigned hsync_pol:1; + unsigned pixclk_pol:1; + unsigned data_pol:1; + unsigned sens_clksrc:1; + unsigned pack_tight:1; + unsigned force_eof:1; + unsigned data_en_pol:1; + + unsigned data_fmt; + unsigned mipi_dt; +}; + +/* + * Enumeration of CSI data bus widths. + */ +enum ipu_csi_data_width { + IPU_CSI_DATA_WIDTH_4 = 0, + IPU_CSI_DATA_WIDTH_8 = 1, + IPU_CSI_DATA_WIDTH_10 = 3, + IPU_CSI_DATA_WIDTH_12 = 5, + IPU_CSI_DATA_WIDTH_16 = 9, +}; + +/* + * Enumeration of CSI clock modes. + */ +enum ipu_csi_clk_mode { + IPU_CSI_CLK_MODE_GATED_CLK, + IPU_CSI_CLK_MODE_NONGATED_CLK, + IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE, + IPU_CSI_CLK_MODE_CCIR656_INTERLACED, + IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR, + IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR, + IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR, + IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR, +}; + +static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset) +{ + return readl(csi->base + offset); +} + +static inline void ipu_csi_write(struct ipu_csi *csi, u32 value, + unsigned offset) +{ + writel(value, csi->base + offset); +} + +/* + * Set mclk division ratio for generating test mode mclk. Only used + * for test generator. + */ +static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk, + u32 ipu_clk) +{ + u32 temp; + u32 div_ratio; + + div_ratio = (ipu_clk / pixel_clk) - 1; + + if (div_ratio > 0xFF || div_ratio < 0) { + dev_err(csi->ipu->dev, + "value of pixel_clk extends normal range\n"); + return -EINVAL; + } + + temp = ipu_csi_read(csi, CSI_SENS_CONF); + temp &= ~CSI_SENS_CONF_DIVRATIO_MASK; + ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT), + CSI_SENS_CONF); + + return 0; +} + +/* + * Find the CSI data format and data width for the given V4L2 media + * bus pixel format code. + */ +static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) +{ + switch (mbus_code) { + case V4L2_MBUS_FMT_BGR565_2X8_BE: + case V4L2_MBUS_FMT_BGR565_2X8_LE: + case V4L2_MBUS_FMT_RGB565_2X8_BE: + case V4L2_MBUS_FMT_RGB565_2X8_LE: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565; + cfg->mipi_dt = MIPI_DT_RGB565; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + break; + case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE: + case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444; + cfg->mipi_dt = MIPI_DT_RGB444; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + break; + case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: + case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555; + cfg->mipi_dt = MIPI_DT_RGB555; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + break; + case V4L2_MBUS_FMT_UYVY8_2X8: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY; + cfg->mipi_dt = MIPI_DT_YUV422; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + break; + case V4L2_MBUS_FMT_YUYV8_2X8: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV; + cfg->mipi_dt = MIPI_DT_YUV422; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + break; + case V4L2_MBUS_FMT_UYVY8_1X16: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY; + cfg->mipi_dt = MIPI_DT_YUV422; + cfg->data_width = IPU_CSI_DATA_WIDTH_16; + break; + case V4L2_MBUS_FMT_YUYV8_1X16: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV; + cfg->mipi_dt = MIPI_DT_YUV422; + cfg->data_width = IPU_CSI_DATA_WIDTH_16; + break; + case V4L2_MBUS_FMT_SBGGR8_1X8: + case V4L2_MBUS_FMT_SGBRG8_1X8: + case V4L2_MBUS_FMT_SGRBG8_1X8: + case V4L2_MBUS_FMT_SRGGB8_1X8: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; + cfg->mipi_dt = MIPI_DT_RAW8; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + break; + case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8: + case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8: + case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: + case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8: + case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE: + case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: + case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE: + case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; + cfg->mipi_dt = MIPI_DT_RAW10; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + break; + case V4L2_MBUS_FMT_SBGGR10_1X10: + case V4L2_MBUS_FMT_SGBRG10_1X10: + case V4L2_MBUS_FMT_SGRBG10_1X10: + case V4L2_MBUS_FMT_SRGGB10_1X10: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; + cfg->mipi_dt = MIPI_DT_RAW10; + cfg->data_width = IPU_CSI_DATA_WIDTH_10; + break; + case V4L2_MBUS_FMT_SBGGR12_1X12: + case V4L2_MBUS_FMT_SGBRG12_1X12: + case V4L2_MBUS_FMT_SGRBG12_1X12: + case V4L2_MBUS_FMT_SRGGB12_1X12: + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; + cfg->mipi_dt = MIPI_DT_RAW12; + cfg->data_width = IPU_CSI_DATA_WIDTH_12; + break; + case V4L2_MBUS_FMT_JPEG_1X8: + /* TODO */ + cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG; + cfg->mipi_dt = MIPI_DT_RAW8; + cfg->data_width = IPU_CSI_DATA_WIDTH_8; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * Fill a CSI bus config struct from mbus_config and mbus_framefmt. + */ +static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, + struct v4l2_mbus_config *mbus_cfg, + struct v4l2_mbus_framefmt *mbus_fmt) +{ + memset(csicfg, 0, sizeof(*csicfg)); + + mbus_code_to_bus_cfg(csicfg, mbus_fmt->code); + + switch (mbus_cfg->type) { + case V4L2_MBUS_PARALLEL: + csicfg->ext_vsync = 1; + csicfg->vsync_pol = (mbus_cfg->flags & + V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0; + csicfg->hsync_pol = (mbus_cfg->flags & + V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0; + csicfg->pixclk_pol = (mbus_cfg->flags & + V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0; + csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; + break; + case V4L2_MBUS_BT656: + csicfg->ext_vsync = 0; + if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field)) + csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; + else + csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; + break; + case V4L2_MBUS_CSI2: + /* + * MIPI CSI-2 requires non gated clock mode, all other + * parameters are not applicable for MIPI CSI-2 bus. + */ + csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK; + break; + default: + /* will never get here, keep compiler quiet */ + break; + } +} + +int ipu_csi_init_interface(struct ipu_csi *csi, + struct v4l2_mbus_config *mbus_cfg, + struct v4l2_mbus_framefmt *mbus_fmt) +{ + struct ipu_csi_bus_config cfg; + unsigned long flags; + u32 data = 0; + + fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt); + + /* Set the CSI_SENS_CONF register remaining fields */ + data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT | + cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT | + cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT | + cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT | + cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT | + cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT | + cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT | + cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT | + cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT | + cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT | + cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT; + + spin_lock_irqsave(&csi->lock, flags); + + ipu_csi_write(csi, data, CSI_SENS_CONF); + + /* Setup sensor frame size */ + ipu_csi_write(csi, + (mbus_fmt->width - 1) | ((mbus_fmt->height - 1) << 16), + CSI_SENS_FRM_SIZE); + + /* Set CCIR registers */ + + switch (cfg.clk_mode) { + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: + ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1); + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); + break; + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: + if (mbus_fmt->width == 720 && mbus_fmt->height == 576) { + /* + * PAL case + * + * Field0BlankEnd = 0x6, Field0BlankStart = 0x2, + * Field0ActiveEnd = 0x4, Field0ActiveStart = 0 + * Field1BlankEnd = 0x7, Field1BlankStart = 0x3, + * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1 + */ + ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN, + CSI_CCIR_CODE_1); + ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2); + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); + + } else if (mbus_fmt->width == 720 && mbus_fmt->height == 480) { + /* + * NTSC case + * + * Field0BlankEnd = 0x7, Field0BlankStart = 0x3, + * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1 + * Field1BlankEnd = 0x6, Field1BlankStart = 0x2, + * Field1ActiveEnd = 0x4, Field1ActiveStart = 0 + */ + ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN, + CSI_CCIR_CODE_1); + ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2); + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); + } else { + dev_err(csi->ipu->dev, + "Unsupported CCIR656 interlaced video mode\n"); + spin_unlock_irqrestore(&csi->lock, flags); + return -EINVAL; + } + break; + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: + ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN, + CSI_CCIR_CODE_1); + ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); + break; + case IPU_CSI_CLK_MODE_GATED_CLK: + case IPU_CSI_CLK_MODE_NONGATED_CLK: + ipu_csi_write(csi, 0, CSI_CCIR_CODE_1); + break; + } + + dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n", + ipu_csi_read(csi, CSI_SENS_CONF)); + dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n", + ipu_csi_read(csi, CSI_ACT_FRM_SIZE)); + + spin_unlock_irqrestore(&csi->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_csi_init_interface); + +bool ipu_csi_is_interlaced(struct ipu_csi *csi) +{ + unsigned long flags; + u32 sensor_protocol; + + spin_lock_irqsave(&csi->lock, flags); + sensor_protocol = + (ipu_csi_read(csi, CSI_SENS_CONF) & + CSI_SENS_CONF_SENS_PRTCL_MASK) >> + CSI_SENS_CONF_SENS_PRTCL_SHIFT; + spin_unlock_irqrestore(&csi->lock, flags); + + switch (sensor_protocol) { + case IPU_CSI_CLK_MODE_GATED_CLK: + case IPU_CSI_CLK_MODE_NONGATED_CLK: + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: + return false; + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: + return true; + default: + dev_err(csi->ipu->dev, + "CSI %d sensor protocol unsupported\n", csi->id); + return false; + } +} +EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced); + +void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w) +{ + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&csi->lock, flags); + + reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE); + w->width = (reg & 0xFFFF) + 1; + w->height = (reg >> 16 & 0xFFFF) + 1; + + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL); + w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT; + w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT; + + spin_unlock_irqrestore(&csi->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_csi_get_window); + +void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w) +{ + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&csi->lock, flags); + + ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16), + CSI_ACT_FRM_SIZE); + + reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL); + reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK); + reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT)); + ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL); + + spin_unlock_irqrestore(&csi->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_csi_set_window); + +void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active, + u32 r_value, u32 g_value, u32 b_value, + u32 pix_clk) +{ + unsigned long flags; + u32 ipu_clk = clk_get_rate(csi->clk_ipu); + u32 temp; + + spin_lock_irqsave(&csi->lock, flags); + + temp = ipu_csi_read(csi, CSI_TST_CTRL); + + if (active == false) { + temp &= ~CSI_TEST_GEN_MODE_EN; + ipu_csi_write(csi, temp, CSI_TST_CTRL); + } else { + /* Set sensb_mclk div_ratio */ + ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk); + + temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK | + CSI_TEST_GEN_B_MASK); + temp |= CSI_TEST_GEN_MODE_EN; + temp |= (r_value << CSI_TEST_GEN_R_SHIFT) | + (g_value << CSI_TEST_GEN_G_SHIFT) | + (b_value << CSI_TEST_GEN_B_SHIFT); + ipu_csi_write(csi, temp, CSI_TST_CTRL); + } + + spin_unlock_irqrestore(&csi->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator); + +int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc, + struct v4l2_mbus_framefmt *mbus_fmt) +{ + struct ipu_csi_bus_config cfg; + unsigned long flags; + u32 temp; + + if (vc > 3) + return -EINVAL; + + mbus_code_to_bus_cfg(&cfg, mbus_fmt->code); + + spin_lock_irqsave(&csi->lock, flags); + + temp = ipu_csi_read(csi, CSI_MIPI_DI); + temp &= ~(0xff << (vc * 8)); + temp |= (cfg.mipi_dt << (vc * 8)); + ipu_csi_write(csi, temp, CSI_MIPI_DI); + + spin_unlock_irqrestore(&csi->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype); + +int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip, + u32 max_ratio, u32 id) +{ + unsigned long flags; + u32 temp; + + if (max_ratio > 5 || id > 3) + return -EINVAL; + + spin_lock_irqsave(&csi->lock, flags); + + temp = ipu_csi_read(csi, CSI_SKIP); + temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK | + CSI_SKIP_SMFC_MASK); + temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) | + (id << CSI_ID_2_SKIP_SHIFT) | + (skip << CSI_SKIP_SMFC_SHIFT); + ipu_csi_write(csi, temp, CSI_SKIP); + + spin_unlock_irqrestore(&csi->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc); + +int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest) +{ + unsigned long flags; + u32 csi_sens_conf, dest; + + if (csi_dest == IPU_CSI_DEST_IDMAC) + dest = CSI_DATA_DEST_IDMAC; + else + dest = CSI_DATA_DEST_IC; /* IC or VDIC */ + + spin_lock_irqsave(&csi->lock, flags); + + csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF); + csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK; + csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT); + ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF); + + spin_unlock_irqrestore(&csi->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_csi_set_dest); + +int ipu_csi_enable(struct ipu_csi *csi) +{ + ipu_module_enable(csi->ipu, csi->module); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_csi_enable); + +int ipu_csi_disable(struct ipu_csi *csi) +{ + ipu_module_disable(csi->ipu, csi->module); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_csi_disable); + +struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id) +{ + unsigned long flags; + struct ipu_csi *csi, *ret; + + if (id > 1) + return ERR_PTR(-EINVAL); + + csi = ipu->csi_priv[id]; + ret = csi; + + spin_lock_irqsave(&csi->lock, flags); + + if (csi->inuse) { + ret = ERR_PTR(-EBUSY); + goto unlock; + } + + csi->inuse = true; +unlock: + spin_unlock_irqrestore(&csi->lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(ipu_csi_get); + +void ipu_csi_put(struct ipu_csi *csi) +{ + unsigned long flags; + + spin_lock_irqsave(&csi->lock, flags); + csi->inuse = false; + spin_unlock_irqrestore(&csi->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_csi_put); + +int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id, + unsigned long base, u32 module, struct clk *clk_ipu) +{ + struct ipu_csi *csi; + + if (id > 1) + return -ENODEV; + + csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL); + if (!csi) + return -ENOMEM; + + ipu->csi_priv[id] = csi; + + spin_lock_init(&csi->lock); + csi->module = module; + csi->id = id; + csi->clk_ipu = clk_ipu; + csi->base = devm_ioremap(dev, base, PAGE_SIZE); + if (!csi->base) + return -ENOMEM; + + dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n", + id, base, csi->base); + csi->ipu = ipu; + + return 0; +} + +void ipu_csi_exit(struct ipu_soc *ipu, int id) +{ +} + +void ipu_csi_dump(struct ipu_csi *csi) +{ + dev_dbg(csi->ipu->dev, "CSI_SENS_CONF: %08x\n", + ipu_csi_read(csi, CSI_SENS_CONF)); + dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n", + ipu_csi_read(csi, CSI_SENS_FRM_SIZE)); + dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE: %08x\n", + ipu_csi_read(csi, CSI_ACT_FRM_SIZE)); + dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL: %08x\n", + ipu_csi_read(csi, CSI_OUT_FRM_CTRL)); + dev_dbg(csi->ipu->dev, "CSI_TST_CTRL: %08x\n", + ipu_csi_read(csi, CSI_TST_CTRL)); + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1: %08x\n", + ipu_csi_read(csi, CSI_CCIR_CODE_1)); + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2: %08x\n", + ipu_csi_read(csi, CSI_CCIR_CODE_2)); + dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3: %08x\n", + ipu_csi_read(csi, CSI_CCIR_CODE_3)); + dev_dbg(csi->ipu->dev, "CSI_MIPI_DI: %08x\n", + ipu_csi_read(csi, CSI_MIPI_DI)); + dev_dbg(csi->ipu->dev, "CSI_SKIP: %08x\n", + ipu_csi_read(csi, CSI_SKIP)); +} +EXPORT_SYMBOL_GPL(ipu_csi_dump); diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h index 1a5c55c05fe8..9b274f1259e1 100644 --- a/drivers/gpu/ipu-v3/ipu-prv.h +++ b/drivers/gpu/ipu-v3/ipu-prv.h @@ -157,6 +157,7 @@ struct ipuv3_channel { }; struct ipu_cpmem; +struct ipu_csi; struct ipu_dc_priv; struct ipu_dmfc_priv; struct ipu_di; @@ -189,6 +190,7 @@ struct ipu_soc { struct ipu_dp_priv *dp_priv; struct ipu_dmfc_priv *dmfc_priv; struct ipu_di *di_priv[2]; + struct ipu_csi *csi_priv[2]; struct ipu_smfc_priv *smfc_priv; }; @@ -211,6 +213,10 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask); bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno); int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms); +int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id, + unsigned long base, u32 module, struct clk *clk_ipu); +void ipu_csi_exit(struct ipu_soc *ipu, int id); + int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, unsigned long base, u32 module, struct clk *ipu_clk); void ipu_di_exit(struct ipu_soc *ipu, int id); diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index f80fe13b0d4d..6d254275192b 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -16,6 +16,7 @@ #include #include #include +#include struct ipu_soc; @@ -61,6 +62,15 @@ struct ipu_di_signal_cfg { u8 vsync_pin; }; +/* + * Enumeration of CSI destinations + */ +enum ipu_csi_dest { + IPU_CSI_DEST_IDMAC, /* to memory via SMFC */ + IPU_CSI_DEST_IC, /* to Image Converter */ + IPU_CSI_DEST_VDIC, /* to VDIC */ +}; + enum ipu_color_space { IPUV3_COLORSPACE_RGB, IPUV3_COLORSPACE_YUV, @@ -211,8 +221,26 @@ int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha, /* * IPU CMOS Sensor Interface (csi) functions */ -int ipu_csi_enable(struct ipu_soc *ipu, int csi); -int ipu_csi_disable(struct ipu_soc *ipu, int csi); +struct ipu_csi; +int ipu_csi_init_interface(struct ipu_csi *csi, + struct v4l2_mbus_config *mbus_cfg, + struct v4l2_mbus_framefmt *mbus_fmt); +bool ipu_csi_is_interlaced(struct ipu_csi *csi); +void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w); +void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w); +void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active, + u32 r_value, u32 g_value, u32 b_value, + u32 pix_clk); +int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc, + struct v4l2_mbus_framefmt *mbus_fmt); +int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip, + u32 max_ratio, u32 id); +int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest); +int ipu_csi_enable(struct ipu_csi *csi); +int ipu_csi_disable(struct ipu_csi *csi); +struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id); +void ipu_csi_put(struct ipu_csi *csi); +void ipu_csi_dump(struct ipu_csi *csi); /* * IPU Sensor Multiple FIFO Controller (SMFC) functions -- GitLab From 1aa8ea0d2bd5d4ba7b5d2b132a02157bc1fb9793 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Mon, 11 Aug 2014 13:04:50 +0200 Subject: [PATCH 0828/5088] gpu: ipu-v3: Add Image Converter unit Adds the Image Converter (IC) unit. Signed-off-by: Steve Longerbeam Condensed the three CSC setup functions into a single one that uses static tables to set up the CSC task parameters. Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/Makefile | 2 +- drivers/gpu/ipu-v3/ipu-common.c | 19 +- drivers/gpu/ipu-v3/ipu-ic.c | 778 ++++++++++++++++++++++++++++++++ drivers/gpu/ipu-v3/ipu-prv.h | 6 + include/video/imx-ipu-v3.h | 45 ++ 5 files changed, 848 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/ipu-v3/ipu-ic.c diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile index d22bd06caa6d..107ec236a4a6 100644 --- a/drivers/gpu/ipu-v3/Makefile +++ b/drivers/gpu/ipu-v3/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \ - ipu-dp.o ipu-dmfc.o ipu-smfc.o + ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 511c364231a2..312eef6ffcad 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -429,6 +429,7 @@ struct ipu_devtype { unsigned long tpm_ofs; unsigned long csi0_ofs; unsigned long csi1_ofs; + unsigned long ic_ofs; unsigned long disp0_ofs; unsigned long disp1_ofs; unsigned long dc_tmpl_ofs; @@ -444,6 +445,7 @@ static struct ipu_devtype ipu_type_imx51 = { .tpm_ofs = 0x1f060000, .csi0_ofs = 0x1f030000, .csi1_ofs = 0x1f038000, + .ic_ofs = 0x1f020000, .disp0_ofs = 0x1e040000, .disp1_ofs = 0x1e048000, .dc_tmpl_ofs = 0x1f080000, @@ -459,6 +461,7 @@ static struct ipu_devtype ipu_type_imx53 = { .tpm_ofs = 0x07060000, .csi0_ofs = 0x07030000, .csi1_ofs = 0x07038000, + .ic_ofs = 0x07020000, .disp0_ofs = 0x06040000, .disp1_ofs = 0x06048000, .dc_tmpl_ofs = 0x07080000, @@ -474,6 +477,7 @@ static struct ipu_devtype ipu_type_imx6q = { .tpm_ofs = 0x00360000, .csi0_ofs = 0x00230000, .csi1_ofs = 0x00238000, + .ic_ofs = 0x00220000, .disp0_ofs = 0x00240000, .disp1_ofs = 0x00248000, .dc_tmpl_ofs = 0x00380000, @@ -518,8 +522,16 @@ static int ipu_submodules_init(struct ipu_soc *ipu, goto err_csi_1; } + ret = ipu_ic_init(ipu, dev, + ipu_base + devtype->ic_ofs, + ipu_base + devtype->tpm_ofs); + if (ret) { + unit = "ic"; + goto err_ic; + } + ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, - IPU_CONF_DI0_EN, ipu_clk); + IPU_CONF_DI0_EN, ipu_clk); if (ret) { unit = "di0"; goto err_di_0; @@ -572,6 +584,8 @@ static int ipu_submodules_init(struct ipu_soc *ipu, err_di_1: ipu_di_exit(ipu, 0); err_di_0: + ipu_ic_exit(ipu); +err_ic: ipu_csi_exit(ipu, 1); err_csi_1: ipu_csi_exit(ipu, 0); @@ -654,6 +668,7 @@ static void ipu_submodules_exit(struct ipu_soc *ipu) ipu_dc_exit(ipu); ipu_di_exit(ipu, 1); ipu_di_exit(ipu, 0); + ipu_ic_exit(ipu); ipu_csi_exit(ipu, 1); ipu_csi_exit(ipu, 0); ipu_cpmem_exit(ipu); @@ -879,6 +894,8 @@ static int ipu_probe(struct platform_device *pdev) ipu_base + devtype->csi0_ofs); dev_dbg(&pdev->dev, "csi1: 0x%08lx\n", ipu_base + devtype->csi1_ofs); + dev_dbg(&pdev->dev, "ic: 0x%08lx\n", + ipu_base + devtype->ic_ofs); dev_dbg(&pdev->dev, "disp0: 0x%08lx\n", ipu_base + devtype->disp0_ofs); dev_dbg(&pdev->dev, "disp1: 0x%08lx\n", diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c new file mode 100644 index 000000000000..ad75588e1629 --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-ic.c @@ -0,0 +1,778 @@ +/* + * Copyright (C) 2012-2014 Mentor Graphics Inc. + * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ipu-prv.h" + +/* IC Register Offsets */ +#define IC_CONF 0x0000 +#define IC_PRP_ENC_RSC 0x0004 +#define IC_PRP_VF_RSC 0x0008 +#define IC_PP_RSC 0x000C +#define IC_CMBP_1 0x0010 +#define IC_CMBP_2 0x0014 +#define IC_IDMAC_1 0x0018 +#define IC_IDMAC_2 0x001C +#define IC_IDMAC_3 0x0020 +#define IC_IDMAC_4 0x0024 + +/* IC Register Fields */ +#define IC_CONF_PRPENC_EN (1 << 0) +#define IC_CONF_PRPENC_CSC1 (1 << 1) +#define IC_CONF_PRPENC_ROT_EN (1 << 2) +#define IC_CONF_PRPVF_EN (1 << 8) +#define IC_CONF_PRPVF_CSC1 (1 << 9) +#define IC_CONF_PRPVF_CSC2 (1 << 10) +#define IC_CONF_PRPVF_CMB (1 << 11) +#define IC_CONF_PRPVF_ROT_EN (1 << 12) +#define IC_CONF_PP_EN (1 << 16) +#define IC_CONF_PP_CSC1 (1 << 17) +#define IC_CONF_PP_CSC2 (1 << 18) +#define IC_CONF_PP_CMB (1 << 19) +#define IC_CONF_PP_ROT_EN (1 << 20) +#define IC_CONF_IC_GLB_LOC_A (1 << 28) +#define IC_CONF_KEY_COLOR_EN (1 << 29) +#define IC_CONF_RWS_EN (1 << 30) +#define IC_CONF_CSI_MEM_WR_EN (1 << 31) + +#define IC_IDMAC_1_CB0_BURST_16 (1 << 0) +#define IC_IDMAC_1_CB1_BURST_16 (1 << 1) +#define IC_IDMAC_1_CB2_BURST_16 (1 << 2) +#define IC_IDMAC_1_CB3_BURST_16 (1 << 3) +#define IC_IDMAC_1_CB4_BURST_16 (1 << 4) +#define IC_IDMAC_1_CB5_BURST_16 (1 << 5) +#define IC_IDMAC_1_CB6_BURST_16 (1 << 6) +#define IC_IDMAC_1_CB7_BURST_16 (1 << 7) +#define IC_IDMAC_1_PRPENC_ROT_MASK (0x7 << 11) +#define IC_IDMAC_1_PRPENC_ROT_OFFSET 11 +#define IC_IDMAC_1_PRPVF_ROT_MASK (0x7 << 14) +#define IC_IDMAC_1_PRPVF_ROT_OFFSET 14 +#define IC_IDMAC_1_PP_ROT_MASK (0x7 << 17) +#define IC_IDMAC_1_PP_ROT_OFFSET 17 +#define IC_IDMAC_1_PP_FLIP_RS (1 << 22) +#define IC_IDMAC_1_PRPVF_FLIP_RS (1 << 21) +#define IC_IDMAC_1_PRPENC_FLIP_RS (1 << 20) + +#define IC_IDMAC_2_PRPENC_HEIGHT_MASK (0x3ff << 0) +#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0 +#define IC_IDMAC_2_PRPVF_HEIGHT_MASK (0x3ff << 10) +#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET 10 +#define IC_IDMAC_2_PP_HEIGHT_MASK (0x3ff << 20) +#define IC_IDMAC_2_PP_HEIGHT_OFFSET 20 + +#define IC_IDMAC_3_PRPENC_WIDTH_MASK (0x3ff << 0) +#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET 0 +#define IC_IDMAC_3_PRPVF_WIDTH_MASK (0x3ff << 10) +#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET 10 +#define IC_IDMAC_3_PP_WIDTH_MASK (0x3ff << 20) +#define IC_IDMAC_3_PP_WIDTH_OFFSET 20 + +struct ic_task_regoffs { + u32 rsc; + u32 tpmem_csc[2]; +}; + +struct ic_task_bitfields { + u32 ic_conf_en; + u32 ic_conf_rot_en; + u32 ic_conf_cmb_en; + u32 ic_conf_csc1_en; + u32 ic_conf_csc2_en; + u32 ic_cmb_galpha_bit; +}; + +static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = { + [IC_TASK_ENCODER] = { + .rsc = IC_PRP_ENC_RSC, + .tpmem_csc = {0x2008, 0}, + }, + [IC_TASK_VIEWFINDER] = { + .rsc = IC_PRP_VF_RSC, + .tpmem_csc = {0x4028, 0x4040}, + }, + [IC_TASK_POST_PROCESSOR] = { + .rsc = IC_PP_RSC, + .tpmem_csc = {0x6060, 0x6078}, + }, +}; + +static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = { + [IC_TASK_ENCODER] = { + .ic_conf_en = IC_CONF_PRPENC_EN, + .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN, + .ic_conf_cmb_en = 0, /* NA */ + .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1, + .ic_conf_csc2_en = 0, /* NA */ + .ic_cmb_galpha_bit = 0, /* NA */ + }, + [IC_TASK_VIEWFINDER] = { + .ic_conf_en = IC_CONF_PRPVF_EN, + .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN, + .ic_conf_cmb_en = IC_CONF_PRPVF_CMB, + .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1, + .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2, + .ic_cmb_galpha_bit = 0, + }, + [IC_TASK_POST_PROCESSOR] = { + .ic_conf_en = IC_CONF_PP_EN, + .ic_conf_rot_en = IC_CONF_PP_ROT_EN, + .ic_conf_cmb_en = IC_CONF_PP_CMB, + .ic_conf_csc1_en = IC_CONF_PP_CSC1, + .ic_conf_csc2_en = IC_CONF_PP_CSC2, + .ic_cmb_galpha_bit = 8, + }, +}; + +struct ipu_ic_priv; + +struct ipu_ic { + enum ipu_ic_task task; + const struct ic_task_regoffs *reg; + const struct ic_task_bitfields *bit; + + enum ipu_color_space in_cs, g_in_cs; + enum ipu_color_space out_cs; + bool graphics; + bool rotation; + bool in_use; + + struct ipu_ic_priv *priv; +}; + +struct ipu_ic_priv { + void __iomem *base; + void __iomem *tpmem_base; + spinlock_t lock; + struct ipu_soc *ipu; + int use_count; + struct ipu_ic task[IC_NUM_TASKS]; +}; + +static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset) +{ + return readl(ic->priv->base + offset); +} + +static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset) +{ + writel(value, ic->priv->base + offset); +} + +struct ic_csc_params { + s16 coeff[3][3]; /* signed 9-bit integer coefficients */ + s16 offset[3]; /* signed 11+2-bit fixed point offset */ + u8 scale:2; /* scale coefficients * 2^(scale-1) */ + bool sat:1; /* saturate to (16, 235(Y) / 240(U, V)) */ +}; + +/* + * Y = R * .299 + G * .587 + B * .114; + * U = R * -.169 + G * -.332 + B * .500 + 128.; + * V = R * .500 + G * -.419 + B * -.0813 + 128.; + */ +static const struct ic_csc_params ic_csc_rgb2ycbcr = { + .coeff = { + { 77, 150, 29 }, + { 469, 427, 128 }, + { 128, 405, 491 }, + }, + .offset = { 0, 512, 512 }, + .scale = 1, +}; + +/* transparent RGB->RGB matrix for graphics combining */ +static const struct ic_csc_params ic_csc_rgb2rgb = { + .coeff = { + { 128, 0, 0 }, + { 0, 128, 0 }, + { 0, 0, 128 }, + }, + .scale = 2, +}; + +/* + * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128)); + * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128)); + * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); + */ +static const struct ic_csc_params ic_csc_ycbcr2rgb = { + .coeff = { + { 149, 0, 204 }, + { 149, 462, 408 }, + { 149, 255, 0 }, + }, + .offset = { -446, 266, -554 }, + .scale = 2, +}; + +static int init_csc(struct ipu_ic *ic, + enum ipu_color_space inf, + enum ipu_color_space outf, + int csc_index) +{ + struct ipu_ic_priv *priv = ic->priv; + const struct ic_csc_params *params; + u32 __iomem *base; + const u16 (*c)[3]; + const u16 *a; + u32 param; + + base = (u32 __iomem *) + (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]); + + if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB) + params = &ic_csc_ycbcr2rgb; + else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV) + params = &ic_csc_rgb2ycbcr; + else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB) + params = &ic_csc_rgb2rgb; + else { + dev_err(priv->ipu->dev, "Unsupported color space conversion\n"); + return -EINVAL; + } + + /* Cast to unsigned */ + c = (const u16 (*)[3])params->coeff; + a = (const u16 *)params->offset; + + param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) | + ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff); + writel(param, base++); + + param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) | + (params->sat << 9); + writel(param, base++); + + param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) | + ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff); + writel(param, base++); + + param = ((a[1] & 0x1fe0) >> 5); + writel(param, base++); + + param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) | + ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff); + writel(param, base++); + + param = ((a[2] & 0x1fe0) >> 5); + writel(param, base++); + + return 0; +} + +static int calc_resize_coeffs(struct ipu_ic *ic, + u32 in_size, u32 out_size, + u32 *resize_coeff, + u32 *downsize_coeff) +{ + struct ipu_ic_priv *priv = ic->priv; + struct ipu_soc *ipu = priv->ipu; + u32 temp_size, temp_downsize; + + /* + * Input size cannot be more than 4096, and output size cannot + * be more than 1024 + */ + if (in_size > 4096) { + dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n"); + return -EINVAL; + } + if (out_size > 1024) { + dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n"); + return -EINVAL; + } + + /* Cannot downsize more than 8:1 */ + if ((out_size << 3) < in_size) { + dev_err(ipu->dev, "Unsupported downsize\n"); + return -EINVAL; + } + + /* Compute downsizing coefficient */ + temp_downsize = 0; + temp_size = in_size; + while (((temp_size > 1024) || (temp_size >= out_size * 2)) && + (temp_downsize < 2)) { + temp_size >>= 1; + temp_downsize++; + } + *downsize_coeff = temp_downsize; + + /* + * compute resizing coefficient using the following equation: + * resize_coeff = M * (SI - 1) / (SO - 1) + * where M = 2^13, SI = input size, SO = output size + */ + *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1); + if (*resize_coeff >= 16384L) { + dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n"); + *resize_coeff = 0x3FFF; + } + + return 0; +} + +void ipu_ic_task_enable(struct ipu_ic *ic) +{ + struct ipu_ic_priv *priv = ic->priv; + unsigned long flags; + u32 ic_conf; + + spin_lock_irqsave(&priv->lock, flags); + + ic_conf = ipu_ic_read(ic, IC_CONF); + + ic_conf |= ic->bit->ic_conf_en; + + if (ic->rotation) + ic_conf |= ic->bit->ic_conf_rot_en; + + if (ic->in_cs != ic->out_cs) + ic_conf |= ic->bit->ic_conf_csc1_en; + + if (ic->graphics) { + ic_conf |= ic->bit->ic_conf_cmb_en; + ic_conf |= ic->bit->ic_conf_csc1_en; + + if (ic->g_in_cs != ic->out_cs) + ic_conf |= ic->bit->ic_conf_csc2_en; + } + + ipu_ic_write(ic, ic_conf, IC_CONF); + + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_ic_task_enable); + +void ipu_ic_task_disable(struct ipu_ic *ic) +{ + struct ipu_ic_priv *priv = ic->priv; + unsigned long flags; + u32 ic_conf; + + spin_lock_irqsave(&priv->lock, flags); + + ic_conf = ipu_ic_read(ic, IC_CONF); + + ic_conf &= ~(ic->bit->ic_conf_en | + ic->bit->ic_conf_csc1_en | + ic->bit->ic_conf_rot_en); + if (ic->bit->ic_conf_csc2_en) + ic_conf &= ~ic->bit->ic_conf_csc2_en; + if (ic->bit->ic_conf_cmb_en) + ic_conf &= ~ic->bit->ic_conf_cmb_en; + + ipu_ic_write(ic, ic_conf, IC_CONF); + + ic->rotation = ic->graphics = false; + + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_ic_task_disable); + +int ipu_ic_task_graphics_init(struct ipu_ic *ic, + enum ipu_color_space in_g_cs, + bool galpha_en, u32 galpha, + bool colorkey_en, u32 colorkey) +{ + struct ipu_ic_priv *priv = ic->priv; + unsigned long flags; + u32 reg, ic_conf; + int ret = 0; + + if (ic->task == IC_TASK_ENCODER) + return -EINVAL; + + spin_lock_irqsave(&priv->lock, flags); + + ic_conf = ipu_ic_read(ic, IC_CONF); + + if (!(ic_conf & ic->bit->ic_conf_csc1_en)) { + /* need transparent CSC1 conversion */ + ret = init_csc(ic, IPUV3_COLORSPACE_RGB, + IPUV3_COLORSPACE_RGB, 0); + if (ret) + goto unlock; + } + + ic->g_in_cs = in_g_cs; + + if (ic->g_in_cs != ic->out_cs) { + ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1); + if (ret) + goto unlock; + } + + if (galpha_en) { + ic_conf |= IC_CONF_IC_GLB_LOC_A; + reg = ipu_ic_read(ic, IC_CMBP_1); + reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit); + reg |= (galpha << ic->bit->ic_cmb_galpha_bit); + ipu_ic_write(ic, reg, IC_CMBP_1); + } else + ic_conf &= ~IC_CONF_IC_GLB_LOC_A; + + if (colorkey_en) { + ic_conf |= IC_CONF_KEY_COLOR_EN; + ipu_ic_write(ic, colorkey, IC_CMBP_2); + } else + ic_conf &= ~IC_CONF_KEY_COLOR_EN; + + ipu_ic_write(ic, ic_conf, IC_CONF); + + ic->graphics = true; +unlock: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init); + +int ipu_ic_task_init(struct ipu_ic *ic, + int in_width, int in_height, + int out_width, int out_height, + enum ipu_color_space in_cs, + enum ipu_color_space out_cs) +{ + struct ipu_ic_priv *priv = ic->priv; + u32 reg, downsize_coeff, resize_coeff; + unsigned long flags; + int ret = 0; + + /* Setup vertical resizing */ + ret = calc_resize_coeffs(ic, in_height, out_height, + &resize_coeff, &downsize_coeff); + if (ret) + return ret; + + reg = (downsize_coeff << 30) | (resize_coeff << 16); + + /* Setup horizontal resizing */ + ret = calc_resize_coeffs(ic, in_width, out_width, + &resize_coeff, &downsize_coeff); + if (ret) + return ret; + + reg |= (downsize_coeff << 14) | resize_coeff; + + spin_lock_irqsave(&priv->lock, flags); + + ipu_ic_write(ic, reg, ic->reg->rsc); + + /* Setup color space conversion */ + ic->in_cs = in_cs; + ic->out_cs = out_cs; + + if (ic->in_cs != ic->out_cs) { + ret = init_csc(ic, ic->in_cs, ic->out_cs, 0); + if (ret) + goto unlock; + } + +unlock: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(ipu_ic_task_init); + +int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel, + u32 width, u32 height, int burst_size, + enum ipu_rotate_mode rot) +{ + struct ipu_ic_priv *priv = ic->priv; + struct ipu_soc *ipu = priv->ipu; + u32 ic_idmac_1, ic_idmac_2, ic_idmac_3; + u32 temp_rot = bitrev8(rot) >> 5; + bool need_hor_flip = false; + unsigned long flags; + int ret = 0; + + if ((burst_size != 8) && (burst_size != 16)) { + dev_err(ipu->dev, "Illegal burst length for IC\n"); + return -EINVAL; + } + + width--; + height--; + + if (temp_rot & 0x2) /* Need horizontal flip */ + need_hor_flip = true; + + spin_lock_irqsave(&priv->lock, flags); + + ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1); + ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2); + ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3); + + switch (channel->num) { + case IPUV3_CHANNEL_IC_PP_MEM: + if (burst_size == 16) + ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16; + else + ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16; + + if (need_hor_flip) + ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS; + else + ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS; + + ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK; + ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET; + + ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK; + ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET; + break; + case IPUV3_CHANNEL_MEM_IC_PP: + if (burst_size == 16) + ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16; + else + ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16; + break; + case IPUV3_CHANNEL_MEM_ROT_PP: + ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK; + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET; + break; + case IPUV3_CHANNEL_MEM_IC_PRP_VF: + if (burst_size == 16) + ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16; + else + ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16; + break; + case IPUV3_CHANNEL_IC_PRP_ENC_MEM: + if (burst_size == 16) + ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16; + else + ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16; + + if (need_hor_flip) + ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS; + else + ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS; + + ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK; + ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET; + + ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK; + ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET; + break; + case IPUV3_CHANNEL_MEM_ROT_ENC: + ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK; + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET; + break; + case IPUV3_CHANNEL_IC_PRP_VF_MEM: + if (burst_size == 16) + ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16; + else + ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16; + + if (need_hor_flip) + ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS; + else + ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS; + + ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK; + ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET; + + ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK; + ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET; + break; + case IPUV3_CHANNEL_MEM_ROT_VF: + ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK; + ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET; + break; + case IPUV3_CHANNEL_G_MEM_IC_PRP_VF: + if (burst_size == 16) + ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16; + else + ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16; + break; + case IPUV3_CHANNEL_G_MEM_IC_PP: + if (burst_size == 16) + ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16; + else + ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16; + break; + case IPUV3_CHANNEL_VDI_MEM_IC_VF: + if (burst_size == 16) + ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16; + else + ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16; + break; + default: + goto unlock; + } + + ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1); + ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2); + ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3); + + if (rot >= IPU_ROTATE_90_RIGHT) + ic->rotation = true; + +unlock: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init); + +int ipu_ic_enable(struct ipu_ic *ic) +{ + struct ipu_ic_priv *priv = ic->priv; + unsigned long flags; + u32 module = IPU_CONF_IC_EN; + + spin_lock_irqsave(&priv->lock, flags); + + if (ic->rotation) + module |= IPU_CONF_ROT_EN; + + if (!priv->use_count) + ipu_module_enable(priv->ipu, module); + + priv->use_count++; + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_ic_enable); + +int ipu_ic_disable(struct ipu_ic *ic) +{ + struct ipu_ic_priv *priv = ic->priv; + unsigned long flags; + u32 module = IPU_CONF_IC_EN | IPU_CONF_ROT_EN; + + spin_lock_irqsave(&priv->lock, flags); + + priv->use_count--; + + if (!priv->use_count) + ipu_module_disable(priv->ipu, module); + + if (priv->use_count < 0) + priv->use_count = 0; + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_ic_disable); + +struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task) +{ + struct ipu_ic_priv *priv = ipu->ic_priv; + unsigned long flags; + struct ipu_ic *ic, *ret; + + if (task >= IC_NUM_TASKS) + return ERR_PTR(-EINVAL); + + ic = &priv->task[task]; + + spin_lock_irqsave(&priv->lock, flags); + + if (ic->in_use) { + ret = ERR_PTR(-EBUSY); + goto unlock; + } + + ic->in_use = true; + ret = ic; + +unlock: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(ipu_ic_get); + +void ipu_ic_put(struct ipu_ic *ic) +{ + struct ipu_ic_priv *priv = ic->priv; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + ic->in_use = false; + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_ic_put); + +int ipu_ic_init(struct ipu_soc *ipu, struct device *dev, + unsigned long base, unsigned long tpmem_base) +{ + struct ipu_ic_priv *priv; + int i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + ipu->ic_priv = priv; + + spin_lock_init(&priv->lock); + priv->base = devm_ioremap(dev, base, PAGE_SIZE); + if (!priv->base) + return -ENOMEM; + priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K); + if (!priv->tpmem_base) + return -ENOMEM; + + dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base); + + priv->ipu = ipu; + + for (i = 0; i < IC_NUM_TASKS; i++) { + priv->task[i].task = i; + priv->task[i].priv = priv; + priv->task[i].reg = &ic_task_reg[i]; + priv->task[i].bit = &ic_task_bit[i]; + } + + return 0; +} + +void ipu_ic_exit(struct ipu_soc *ipu) +{ +} + +void ipu_ic_dump(struct ipu_ic *ic) +{ + struct ipu_ic_priv *priv = ic->priv; + struct ipu_soc *ipu = priv->ipu; + + dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n", + ipu_ic_read(ic, IC_CONF)); + dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n", + ipu_ic_read(ic, IC_PRP_ENC_RSC)); + dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n", + ipu_ic_read(ic, IC_PRP_VF_RSC)); + dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n", + ipu_ic_read(ic, IC_PP_RSC)); + dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n", + ipu_ic_read(ic, IC_CMBP_1)); + dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n", + ipu_ic_read(ic, IC_CMBP_2)); + dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n", + ipu_ic_read(ic, IC_IDMAC_1)); + dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n", + ipu_ic_read(ic, IC_IDMAC_2)); + dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n", + ipu_ic_read(ic, IC_IDMAC_3)); + dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n", + ipu_ic_read(ic, IC_IDMAC_4)); +} +EXPORT_SYMBOL_GPL(ipu_ic_dump); diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h index 9b274f1259e1..1596a4f52faf 100644 --- a/drivers/gpu/ipu-v3/ipu-prv.h +++ b/drivers/gpu/ipu-v3/ipu-prv.h @@ -161,6 +161,7 @@ struct ipu_csi; struct ipu_dc_priv; struct ipu_dmfc_priv; struct ipu_di; +struct ipu_ic_priv; struct ipu_smfc_priv; struct ipu_devtype; @@ -191,6 +192,7 @@ struct ipu_soc { struct ipu_dmfc_priv *dmfc_priv; struct ipu_di *di_priv[2]; struct ipu_csi *csi_priv[2]; + struct ipu_ic_priv *ic_priv; struct ipu_smfc_priv *smfc_priv; }; @@ -217,6 +219,10 @@ int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id, unsigned long base, u32 module, struct clk *clk_ipu); void ipu_csi_exit(struct ipu_soc *ipu, int id); +int ipu_ic_init(struct ipu_soc *ipu, struct device *dev, + unsigned long base, unsigned long tpmem_base); +void ipu_ic_exit(struct ipu_soc *ipu); + int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, unsigned long base, u32 module, struct clk *ipu_clk); void ipu_di_exit(struct ipu_soc *ipu, int id); diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index 6d254275192b..a477814a03af 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -71,6 +71,20 @@ enum ipu_csi_dest { IPU_CSI_DEST_VDIC, /* to VDIC */ }; +/* + * Enumeration of IPU rotation modes + */ +enum ipu_rotate_mode { + IPU_ROTATE_NONE = 0, + IPU_ROTATE_VERT_FLIP, + IPU_ROTATE_HORIZ_FLIP, + IPU_ROTATE_180, + IPU_ROTATE_90_RIGHT, + IPU_ROTATE_90_RIGHT_VFLIP, + IPU_ROTATE_90_RIGHT_HFLIP, + IPU_ROTATE_90_LEFT, +}; + enum ipu_color_space { IPUV3_COLORSPACE_RGB, IPUV3_COLORSPACE_YUV, @@ -242,6 +256,37 @@ struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id); void ipu_csi_put(struct ipu_csi *csi); void ipu_csi_dump(struct ipu_csi *csi); +/* + * IPU Image Converter (ic) functions + */ +enum ipu_ic_task { + IC_TASK_ENCODER, + IC_TASK_VIEWFINDER, + IC_TASK_POST_PROCESSOR, + IC_NUM_TASKS, +}; + +struct ipu_ic; +int ipu_ic_task_init(struct ipu_ic *ic, + int in_width, int in_height, + int out_width, int out_height, + enum ipu_color_space in_cs, + enum ipu_color_space out_cs); +int ipu_ic_task_graphics_init(struct ipu_ic *ic, + enum ipu_color_space in_g_cs, + bool galpha_en, u32 galpha, + bool colorkey_en, u32 colorkey); +void ipu_ic_task_enable(struct ipu_ic *ic); +void ipu_ic_task_disable(struct ipu_ic *ic); +int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel, + u32 width, u32 height, int burst_size, + enum ipu_rotate_mode rot); +int ipu_ic_enable(struct ipu_ic *ic); +int ipu_ic_disable(struct ipu_ic *ic); +struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task); +void ipu_ic_put(struct ipu_ic *ic); +void ipu_ic_dump(struct ipu_ic *ic); + /* * IPU Sensor Multiple FIFO Controller (SMFC) functions */ -- GitLab From fc4353559e587f5962f22c24ca7e015bdbea1e49 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 25 Jun 2014 18:05:33 -0700 Subject: [PATCH 0829/5088] gpu: ipu-v3: smfc: Move enable/disable to ipu-smfc.c Move the SMFC module enable/disable helpers into the ipu-smfc submodule. Signed-off-by: Steve Longerbeam Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-common.c | 12 ------------ drivers/gpu/ipu-v3/ipu-smfc.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 312eef6ffcad..f5a4e1ac2b50 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -217,18 +217,6 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask) } EXPORT_SYMBOL_GPL(ipu_module_disable); -int ipu_smfc_enable(struct ipu_soc *ipu) -{ - return ipu_module_enable(ipu, IPU_CONF_SMFC_EN); -} -EXPORT_SYMBOL_GPL(ipu_smfc_enable); - -int ipu_smfc_disable(struct ipu_soc *ipu) -{ - return ipu_module_disable(ipu, IPU_CONF_SMFC_EN); -} -EXPORT_SYMBOL_GPL(ipu_smfc_disable); - int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel) { struct ipu_soc *ipu = channel->ipu; diff --git a/drivers/gpu/ipu-v3/ipu-smfc.c b/drivers/gpu/ipu-v3/ipu-smfc.c index e4f85ad286fc..87ac624dd7ca 100644 --- a/drivers/gpu/ipu-v3/ipu-smfc.c +++ b/drivers/gpu/ipu-v3/ipu-smfc.c @@ -71,6 +71,18 @@ int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_ } EXPORT_SYMBOL_GPL(ipu_smfc_map_channel); +int ipu_smfc_enable(struct ipu_soc *ipu) +{ + return ipu_module_enable(ipu, IPU_CONF_SMFC_EN); +} +EXPORT_SYMBOL_GPL(ipu_smfc_enable); + +int ipu_smfc_disable(struct ipu_soc *ipu) +{ + return ipu_module_disable(ipu, IPU_CONF_SMFC_EN); +} +EXPORT_SYMBOL_GPL(ipu_smfc_disable); + int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base) { -- GitLab From 7fafa8f06f9bdf32b806b4612bfe387de8e34125 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 25 Jun 2014 18:05:34 -0700 Subject: [PATCH 0830/5088] gpu: ipu-v3: smfc: Convert to per-channel Convert the smfc object to be specific to a single smfc channel. Add ipu_smfc_{get|put} to retrieve and release a single smfc channel for exclusive use, and add use counter to ipu_smfc_{enable|disable}. Signed-off-by: Steve Longerbeam Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-smfc.c | 132 +++++++++++++++++++++++++++------- include/video/imx-ipu-v3.h | 10 +-- 2 files changed, 112 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/ipu-v3/ipu-smfc.c b/drivers/gpu/ipu-v3/ipu-smfc.c index 87ac624dd7ca..a6429ca913c1 100644 --- a/drivers/gpu/ipu-v3/ipu-smfc.c +++ b/drivers/gpu/ipu-v3/ipu-smfc.c @@ -21,9 +21,18 @@ #include "ipu-prv.h" +struct ipu_smfc { + struct ipu_smfc_priv *priv; + int chno; + bool inuse; +}; + struct ipu_smfc_priv { void __iomem *base; spinlock_t lock; + struct ipu_soc *ipu; + struct ipu_smfc channel[4]; + int use_count; }; /*SMFC Registers */ @@ -31,75 +40,146 @@ struct ipu_smfc_priv { #define SMFC_WMC 0x0004 #define SMFC_BS 0x0008 -int ipu_smfc_set_burstsize(struct ipu_soc *ipu, int channel, int burstsize) +int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize) { - struct ipu_smfc_priv *smfc = ipu->smfc_priv; + struct ipu_smfc_priv *priv = smfc->priv; unsigned long flags; u32 val, shift; - spin_lock_irqsave(&smfc->lock, flags); + spin_lock_irqsave(&priv->lock, flags); - shift = channel * 4; - val = readl(smfc->base + SMFC_BS); + shift = smfc->chno * 4; + val = readl(priv->base + SMFC_BS); val &= ~(0xf << shift); val |= burstsize << shift; - writel(val, smfc->base + SMFC_BS); + writel(val, priv->base + SMFC_BS); - spin_unlock_irqrestore(&smfc->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); return 0; } EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize); -int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_id) +int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id) { - struct ipu_smfc_priv *smfc = ipu->smfc_priv; + struct ipu_smfc_priv *priv = smfc->priv; unsigned long flags; u32 val, shift; - spin_lock_irqsave(&smfc->lock, flags); + spin_lock_irqsave(&priv->lock, flags); - shift = channel * 3; - val = readl(smfc->base + SMFC_MAP); + shift = smfc->chno * 3; + val = readl(priv->base + SMFC_MAP); val &= ~(0x7 << shift); val |= ((csi_id << 2) | mipi_id) << shift; - writel(val, smfc->base + SMFC_MAP); + writel(val, priv->base + SMFC_MAP); - spin_unlock_irqrestore(&smfc->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); return 0; } EXPORT_SYMBOL_GPL(ipu_smfc_map_channel); -int ipu_smfc_enable(struct ipu_soc *ipu) +int ipu_smfc_enable(struct ipu_smfc *smfc) { - return ipu_module_enable(ipu, IPU_CONF_SMFC_EN); + struct ipu_smfc_priv *priv = smfc->priv; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + if (!priv->use_count) + ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN); + + priv->use_count++; + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; } EXPORT_SYMBOL_GPL(ipu_smfc_enable); -int ipu_smfc_disable(struct ipu_soc *ipu) +int ipu_smfc_disable(struct ipu_smfc *smfc) { - return ipu_module_disable(ipu, IPU_CONF_SMFC_EN); + struct ipu_smfc_priv *priv = smfc->priv; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + priv->use_count--; + + if (!priv->use_count) + ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN); + + if (priv->use_count < 0) + priv->use_count = 0; + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; } EXPORT_SYMBOL_GPL(ipu_smfc_disable); +struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno) +{ + struct ipu_smfc_priv *priv = ipu->smfc_priv; + struct ipu_smfc *smfc, *ret; + unsigned long flags; + + if (chno >= 4) + return ERR_PTR(-EINVAL); + + smfc = &priv->channel[chno]; + ret = smfc; + + spin_lock_irqsave(&priv->lock, flags); + + if (smfc->inuse) { + ret = ERR_PTR(-EBUSY); + goto unlock; + } + + smfc->inuse = true; +unlock: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(ipu_smfc_get); + +void ipu_smfc_put(struct ipu_smfc *smfc) +{ + struct ipu_smfc_priv *priv = smfc->priv; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + smfc->inuse = false; + spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_smfc_put); + int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base) { - struct ipu_smfc_priv *smfc; + struct ipu_smfc_priv *priv; + int i; - smfc = devm_kzalloc(dev, sizeof(*smfc), GFP_KERNEL); - if (!smfc) + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - ipu->smfc_priv = smfc; - spin_lock_init(&smfc->lock); + ipu->smfc_priv = priv; + spin_lock_init(&priv->lock); + priv->ipu = ipu; - smfc->base = devm_ioremap(dev, base, PAGE_SIZE); - if (!smfc->base) + priv->base = devm_ioremap(dev, base, PAGE_SIZE); + if (!priv->base) return -ENOMEM; - pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, smfc->base); + for (i = 0; i < 4; i++) { + priv->channel[i].priv = priv; + priv->channel[i].chno = i; + } + + pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base); return 0; } diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index a477814a03af..a695ee83e4e1 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -290,10 +290,12 @@ void ipu_ic_dump(struct ipu_ic *ic); /* * IPU Sensor Multiple FIFO Controller (SMFC) functions */ -int ipu_smfc_enable(struct ipu_soc *ipu); -int ipu_smfc_disable(struct ipu_soc *ipu); -int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_id); -int ipu_smfc_set_burstsize(struct ipu_soc *ipu, int channel, int burstsize); +struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno); +void ipu_smfc_put(struct ipu_smfc *smfc); +int ipu_smfc_enable(struct ipu_smfc *smfc); +int ipu_smfc_disable(struct ipu_smfc *smfc); +int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id); +int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize); enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc); enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); -- GitLab From a2be35e3320b27c84488729e9fb56a62e74d65fa Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 25 Jun 2014 18:05:35 -0700 Subject: [PATCH 0831/5088] gpu: ipu-v3: smfc: Add ipu_smfc_set_watermark() Adds ipu_smfc_set_watermark() which programs a channel's SMFC FIFO levels at which the watermark signal is set and cleared. Signed-off-by: Steve Longerbeam Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-smfc.c | 20 ++++++++++++++++++++ include/video/imx-ipu-v3.h | 1 + 2 files changed, 21 insertions(+) diff --git a/drivers/gpu/ipu-v3/ipu-smfc.c b/drivers/gpu/ipu-v3/ipu-smfc.c index a6429ca913c1..6ca9b43ce25a 100644 --- a/drivers/gpu/ipu-v3/ipu-smfc.c +++ b/drivers/gpu/ipu-v3/ipu-smfc.c @@ -80,6 +80,26 @@ int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id) } EXPORT_SYMBOL_GPL(ipu_smfc_map_channel); +int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level) +{ + struct ipu_smfc_priv *priv = smfc->priv; + unsigned long flags; + u32 val, shift; + + spin_lock_irqsave(&priv->lock, flags); + + shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0); + val = readl(priv->base + SMFC_WMC); + val &= ~(0x3f << shift); + val |= ((clr_level << 3) | set_level) << shift; + writel(val, priv->base + SMFC_WMC); + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark); + int ipu_smfc_enable(struct ipu_smfc *smfc) { struct ipu_smfc_priv *priv = smfc->priv; diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index a695ee83e4e1..49e5954ac033 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -296,6 +296,7 @@ int ipu_smfc_enable(struct ipu_smfc *smfc); int ipu_smfc_disable(struct ipu_smfc *smfc); int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id); int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize); +int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level); enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc); enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); -- GitLab From ae0e9708b30b3eebe5a58e4d055eb49a73d641dd Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 25 Jun 2014 18:05:36 -0700 Subject: [PATCH 0832/5088] gpu: ipu-v3: Add ipu_mbus_code_to_colorspace() Add ipu_mbus_code_to_colorspace() to find ipu_color_space from a media bus pixel format code. Signed-off-by: Steve Longerbeam Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-common.c | 13 +++++++++++++ include/video/imx-ipu-v3.h | 1 + 2 files changed, 14 insertions(+) diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index f5a4e1ac2b50..49ee990b4d1f 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -101,6 +101,19 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) } EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace); +enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code) +{ + switch (mbus_code & 0xf000) { + case 0x1000: + return IPUV3_COLORSPACE_RGB; + case 0x2000: + return IPUV3_COLORSPACE_YUV; + default: + return IPUV3_COLORSPACE_UNKNOWN; + } +} +EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace); + struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num) { struct ipuv3_channel *channel; diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index 49e5954ac033..7c97ccaf39f6 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -300,6 +300,7 @@ int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level); enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc); enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); +enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code); struct ipu_client_platformdata { int csi; -- GitLab From f835f386a119c3f78f5acb93e86a4f025211739a Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 25 Jun 2014 18:05:37 -0700 Subject: [PATCH 0833/5088] gpu: ipu-v3: Add rotation mode conversion utilities Add two functions: - ipu_degrees_to_rot_mode(): converts a degrees, hflip, and vflip setting to an IPU rotation mode. - ipu_rot_mode_to_degrees(): converts an IPU rotation mode with given hflip and vflip settings to degrees. Signed-off-by: Steve Longerbeam Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-common.c | 64 +++++++++++++++++++++++++++++++++ include/video/imx-ipu-v3.h | 4 +++ 2 files changed, 68 insertions(+) diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 49ee990b4d1f..a1d42eed5d06 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -114,6 +114,70 @@ enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code) } EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace); +int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees, + bool hflip, bool vflip) +{ + u32 r90, vf, hf; + + switch (degrees) { + case 0: + vf = hf = r90 = 0; + break; + case 90: + vf = hf = 0; + r90 = 1; + break; + case 180: + vf = hf = 1; + r90 = 0; + break; + case 270: + vf = hf = r90 = 1; + break; + default: + return -EINVAL; + } + + hf ^= (u32)hflip; + vf ^= (u32)vflip; + + *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf); + return 0; +} +EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode); + +int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode, + bool hflip, bool vflip) +{ + u32 r90, vf, hf; + + r90 = ((u32)mode >> 2) & 0x1; + hf = ((u32)mode >> 1) & 0x1; + vf = ((u32)mode >> 0) & 0x1; + hf ^= (u32)hflip; + vf ^= (u32)vflip; + + switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) { + case IPU_ROTATE_NONE: + *degrees = 0; + break; + case IPU_ROTATE_90_RIGHT: + *degrees = 90; + break; + case IPU_ROTATE_180: + *degrees = 180; + break; + case IPU_ROTATE_90_LEFT: + *degrees = 270; + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees); + struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num) { struct ipuv3_channel *channel; diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index 7c97ccaf39f6..3562698528bd 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -301,6 +301,10 @@ int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level); enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc); enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code); +int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees, + bool hflip, bool vflip); +int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode, + bool hflip, bool vflip); struct ipu_client_platformdata { int csi; -- GitLab From 4cea940d34319fb5d5e2f4d554e23f766c228e90 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 25 Jun 2014 18:05:38 -0700 Subject: [PATCH 0834/5088] gpu: ipu-v3: Add helper function checking if pixfmt is planar Add simple helper function returning true if passed pixel format is one of supported planar ones. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-common.c | 12 ++++++++++++ include/video/imx-ipu-v3.h | 1 + 2 files changed, 13 insertions(+) diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index a1d42eed5d06..18563c240f10 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -101,6 +101,18 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) } EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace); +bool ipu_pixelformat_is_planar(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + return true; + } + + return false; +} +EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar); + enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code) { switch (mbus_code & 0xf000) { diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index 3562698528bd..ecb01f843aee 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h @@ -301,6 +301,7 @@ int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level); enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc); enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code); +bool ipu_pixelformat_is_planar(u32 pixelformat); int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees, bool hflip, bool vflip); int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode, -- GitLab From a4cd8f229ff71db0c95c0d96381d4fb9239fdb19 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 25 Jun 2014 18:05:39 -0700 Subject: [PATCH 0835/5088] gpu: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h Move the IDMAC channel names to imx-ipu-v3.h, to make the names available outside IPU. Add a couple new channels in the process (async display BG/FG, channels 24 and 29). Signed-off-by: Steve Longerbeam Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-prv.h | 25 ------------------------- include/video/imx-ipu-v3.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h index 1596a4f52faf..7f08a461c929 100644 --- a/drivers/gpu/ipu-v3/ipu-prv.h +++ b/drivers/gpu/ipu-v3/ipu-prv.h @@ -24,31 +24,6 @@ struct ipu_soc; #include